| Directory: | ./ |
|---|---|
| File: | sql/sql_table.cc |
| Date: | 2022-12-06 21:40:42 |
| Exec | Total | Coverage | |
|---|---|---|---|
| Lines: | 6845 | 7613 | 89.9% |
| Branches: | 8880 | 14073 | 63.1% |
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | Copyright (c) 2000, 2022, Oracle and/or its affiliates. | ||
| 3 | |||
| 4 | This program is free software; you can redistribute it and/or modify | ||
| 5 | it under the terms of the GNU General Public License, version 2.0, | ||
| 6 | as published by the Free Software Foundation. | ||
| 7 | |||
| 8 | This program is also distributed with certain software (including | ||
| 9 | but not limited to OpenSSL) that is licensed under separate terms, | ||
| 10 | as designated in a particular file or component or in included license | ||
| 11 | documentation. The authors of MySQL hereby grant you an additional | ||
| 12 | permission to link the program and your derivative works with the | ||
| 13 | separately licensed software that they have included with MySQL. | ||
| 14 | |||
| 15 | This program is distributed in the hope that it will be useful, | ||
| 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 18 | GNU General Public License, version 2.0, for more details. | ||
| 19 | |||
| 20 | You should have received a copy of the GNU General Public License | ||
| 21 | along with this program; if not, write to the Free Software | ||
| 22 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
| 23 | */ | ||
| 24 | |||
| 25 | /* drop and alter of tables */ | ||
| 26 | |||
| 27 | #include "sql/sql_table.h" | ||
| 28 | |||
| 29 | #include <assert.h> | ||
| 30 | #include <errno.h> | ||
| 31 | #include <fcntl.h> | ||
| 32 | #include <stdint.h> | ||
| 33 | #include <stdio.h> | ||
| 34 | #include <string.h> | ||
| 35 | |||
| 36 | #include <algorithm> | ||
| 37 | #include <atomic> | ||
| 38 | #include <functional> | ||
| 39 | #include <memory> | ||
| 40 | #include <optional> | ||
| 41 | #include <string> | ||
| 42 | #include <string_view> | ||
| 43 | #include <type_traits> | ||
| 44 | |||
| 45 | /* HAVE_PSI_*_INTERFACE */ | ||
| 46 | #include "my_psi_config.h" // IWYU pragma: keep | ||
| 47 | |||
| 48 | /* drop_table_share with WITH_LOCK_ORDER */ | ||
| 49 | #include "mysql/psi/psi_table.h" // IWYU pragma: keep | ||
| 50 | |||
| 51 | /* PSI_TABLE_CALL() with WITH_LOCK_ORDER */ | ||
| 52 | #include "mysql/psi/mysql_table.h" // IWYU pragma: keep | ||
| 53 | |||
| 54 | #include "decimal.h" | ||
| 55 | #include "field_types.h" // enum_field_types | ||
| 56 | #include "lex_string.h" | ||
| 57 | #include "libbinlogevents/include/binlog_event.h" | ||
| 58 | #include "m_ctype.h" | ||
| 59 | #include "m_string.h" // my_stpncpy | ||
| 60 | #include "map_helpers.h" | ||
| 61 | #include "mem_root_deque.h" | ||
| 62 | #include "my_alloc.h" | ||
| 63 | #include "my_base.h" | ||
| 64 | #include "my_bitmap.h" | ||
| 65 | #include "my_check_opt.h" // T_EXTEND | ||
| 66 | #include "my_checksum.h" | ||
| 67 | #include "my_compiler.h" | ||
| 68 | #include "my_dbug.h" | ||
| 69 | #include "my_io.h" | ||
| 70 | #include "my_loglevel.h" | ||
| 71 | #include "my_psi_config.h" | ||
| 72 | #include "my_sqlcommand.h" | ||
| 73 | #include "my_sys.h" | ||
| 74 | #include "my_systime.h" | ||
| 75 | #include "my_thread_local.h" | ||
| 76 | #include "my_time.h" | ||
| 77 | #include "mysql/components/services/bits/psi_bits.h" | ||
| 78 | #include "mysql/components/services/bits/psi_stage_bits.h" | ||
| 79 | #include "mysql/components/services/log_builtins.h" | ||
| 80 | #include "mysql/components/services/log_shared.h" | ||
| 81 | #include "mysql/plugin.h" | ||
| 82 | #include "mysql/psi/mysql_mutex.h" | ||
| 83 | #include "mysql/psi/mysql_stage.h" | ||
| 84 | #include "mysql_com.h" | ||
| 85 | #include "mysql_time.h" | ||
| 86 | #include "mysqld_error.h" // ER_* | ||
| 87 | #include "pfs_table_provider.h" | ||
| 88 | #include "prealloced_array.h" | ||
| 89 | #include "scope_guard.h" | ||
| 90 | #include "sql/auth/auth_acls.h" | ||
| 91 | #include "sql/auth/auth_common.h" // check_fk_parent_table_access | ||
| 92 | #include "sql/binlog.h" // mysql_bin_log | ||
| 93 | #include "sql/create_field.h" | ||
| 94 | #include "sql/current_thd.h" | ||
| 95 | #include "sql/dd/cache/dictionary_client.h" // dd::cache::Dictionary_client | ||
| 96 | #include "sql/dd/collection.h" | ||
| 97 | #include "sql/dd/dd.h" // dd::get_dictionary | ||
| 98 | #include "sql/dd/dd_schema.h" // dd::schema_exists | ||
| 99 | #include "sql/dd/dd_table.h" // dd::drop_table, dd::update_keys... | ||
| 100 | #include "sql/dd/dictionary.h" // dd::Dictionary | ||
| 101 | #include "sql/dd/impl/types/index_impl.h" | ||
| 102 | #include "sql/dd/properties.h" // dd::Properties | ||
| 103 | #include "sql/dd/sdi_api.h" // dd::sdi::drop_sdis | ||
| 104 | #include "sql/dd/string_type.h" | ||
| 105 | #include "sql/dd/types/abstract_table.h" | ||
| 106 | #include "sql/dd/types/check_constraint.h" // dd::Check_constraint | ||
| 107 | #include "sql/dd/types/column.h" | ||
| 108 | #include "sql/dd/types/foreign_key.h" // dd::Foreign_key | ||
| 109 | #include "sql/dd/types/foreign_key_element.h" // dd::Foreign_key_element | ||
| 110 | #include "sql/dd/types/index.h" // dd::Index | ||
| 111 | #include "sql/dd/types/index_element.h" // dd::Index_element | ||
| 112 | #include "sql/dd/types/partition.h" // dd::Partition | ||
| 113 | #include "sql/dd/types/schema.h" | ||
| 114 | #include "sql/dd/types/table.h" // dd::Table | ||
| 115 | #include "sql/dd/types/trigger.h" | ||
| 116 | #include "sql/dd_sql_view.h" // update_referencing_views_metadata | ||
| 117 | #include "sql/dd_table_share.h" // open_table_def | ||
| 118 | #include "sql/debug_sync.h" // DEBUG_SYNC | ||
| 119 | #include "sql/derror.h" // ER_THD | ||
| 120 | #include "sql/enum_query_type.h" | ||
| 121 | #include "sql/error_handler.h" // Drop_table_error_handler | ||
| 122 | #include "sql/field.h" | ||
| 123 | #include "sql/field_common_properties.h" | ||
| 124 | #include "sql/filesort.h" // Filesort | ||
| 125 | #include "sql/gis/srid.h" | ||
| 126 | #include "sql/handler.h" | ||
| 127 | #include "sql/histograms/histogram.h" | ||
| 128 | #include "sql/item.h" | ||
| 129 | #include "sql/item_timefunc.h" // Item_func_now_local | ||
| 130 | #include "sql/iterators/row_iterator.h" | ||
| 131 | #include "sql/join_optimizer/access_path.h" | ||
| 132 | #include "sql/join_optimizer/bit_utils.h" | ||
| 133 | #include "sql/key.h" // KEY | ||
| 134 | #include "sql/key_spec.h" // Key_part_spec | ||
| 135 | #include "sql/lock.h" // mysql_lock_remove, lock_tablespace_names | ||
| 136 | #include "sql/locked_tables_list.h" | ||
| 137 | #include "sql/log.h" | ||
| 138 | #include "sql/log_event.h" // Query_log_event | ||
| 139 | #include "sql/mdl.h" | ||
| 140 | #include "sql/mem_root_array.h" | ||
| 141 | #include "sql/my_decimal.h" | ||
| 142 | #include "sql/mysqld.h" // lower_case_table_names | ||
| 143 | #include "sql/partition_element.h" | ||
| 144 | #include "sql/partition_info.h" // partition_info | ||
| 145 | #include "sql/partitioning/partition_handler.h" // Partition_handler | ||
| 146 | #include "sql/protocol.h" | ||
| 147 | #include "sql/psi_memory_key.h" | ||
| 148 | #include "sql/query_options.h" | ||
| 149 | #include "sql/rpl_gtid.h" | ||
| 150 | #include "sql/rpl_rli.h" // rli_slave etc | ||
| 151 | #include "sql/session_tracker.h" | ||
| 152 | #include "sql/sql_alter.h" | ||
| 153 | #include "sql/sql_backup_lock.h" // acquire_shared_backup_lock | ||
| 154 | #include "sql/sql_base.h" // lock_table_names | ||
| 155 | #include "sql/sql_bitmap.h" | ||
| 156 | #include "sql/sql_check_constraint.h" // Sql_check_constraint_spec* | ||
| 157 | #include "sql/sql_class.h" // THD | ||
| 158 | #include "sql/sql_const.h" | ||
| 159 | #include "sql/sql_constraint.h" // Constraint_type_resolver | ||
| 160 | #include "sql/sql_db.h" // get_default_db_collation | ||
| 161 | #include "sql/sql_error.h" | ||
| 162 | #include "sql/sql_executor.h" // unique_ptr_destroy_only<RowIterator> | ||
| 163 | #include "sql/sql_gipk.h" | ||
| 164 | #include "sql/sql_handler.h" | ||
| 165 | #include "sql/sql_lex.h" | ||
| 166 | #include "sql/sql_list.h" | ||
| 167 | #include "sql/sql_parse.h" // test_if_data_home_dir | ||
| 168 | #include "sql/sql_partition.h" | ||
| 169 | #include "sql/sql_plist.h" | ||
| 170 | #include "sql/sql_plugin.h" | ||
| 171 | #include "sql/sql_plugin_ref.h" | ||
| 172 | #include "sql/sql_resolver.h" // setup_order | ||
| 173 | #include "sql/sql_show.h" | ||
| 174 | #include "sql/sql_tablespace.h" // validate_tablespace_name | ||
| 175 | #include "sql/sql_time.h" // make_truncated_value_warning | ||
| 176 | #include "sql/sql_trigger.h" // change_trigger_table_name | ||
| 177 | #include "sql/sql_zip_dict.h" | ||
| 178 | #include "sql/srs_fetcher.h" | ||
| 179 | #include "sql/stateless_allocator.h" | ||
| 180 | #include "sql/strfunc.h" // find_type2 | ||
| 181 | #include "sql/system_variables.h" | ||
| 182 | #include "sql/table.h" | ||
| 183 | #include "sql/thd_raii.h" | ||
| 184 | #include "sql/thr_malloc.h" | ||
| 185 | #include "sql/transaction.h" // trans_commit_stmt | ||
| 186 | #include "sql/transaction_info.h" | ||
| 187 | #include "sql/trigger.h" | ||
| 188 | #include "sql/xa.h" | ||
| 189 | #include "sql_string.h" | ||
| 190 | #include "sql_zip_dict.h" | ||
| 191 | #include "template_utils.h" | ||
| 192 | #include "thr_lock.h" | ||
| 193 | #include "typelib.h" | ||
| 194 | |||
| 195 | namespace dd { | ||
| 196 | class View; | ||
| 197 | } // namespace dd | ||
| 198 | |||
| 199 | using binary_log::checksum_crc32; | ||
| 200 | using std::max; | ||
| 201 | using std::min; | ||
| 202 | using std::string; | ||
| 203 | using std::to_string; | ||
| 204 | |||
| 205 | /** Don't pack string keys shorter than this (if PACK_KEYS=1 isn't used). */ | ||
| 206 | static constexpr const int KEY_DEFAULT_PACK_LENGTH{8}; | ||
| 207 | /* Max number of enumeration values */ | ||
| 208 | static constexpr const int MAX_ENUM_VALUES{65535}; | ||
| 209 | |||
| 210 | #define ER_THD_OR_DEFAULT(thd, X) \ | ||
| 211 | ((thd) ? ER_THD_NONCONST(thd, X) : ER_DEFAULT_NONCONST(X)) | ||
| 212 | |||
| 213 | const char *primary_key_name = "PRIMARY"; | ||
| 214 | namespace { | ||
| 215 | 847809 | bool is_temp_table(const HA_CREATE_INFO &ci) { | |
| 216 | 847809 | return (ci.options & HA_LEX_CREATE_TMP_TABLE); | |
| 217 | } | ||
| 218 | |||
| 219 | 1342807 | bool is_engine_specified(const HA_CREATE_INFO &ci) { | |
| 220 |
3/4✓ Branch 0 taken 1102295 times.
✓ Branch 1 taken 240512 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1102295 times.
|
1342807 | assert((ci.used_fields & HA_CREATE_USED_ENGINE) == 0 || |
| 221 | ci.db_type != nullptr); | ||
| 222 | 1342807 | return (ci.used_fields & HA_CREATE_USED_ENGINE); | |
| 223 | } | ||
| 224 | |||
| 225 | 173641 | handlerton *default_handlerton(THD *thd, const HA_CREATE_INFO &ci) { | |
| 226 |
2/2✓ Branch 0 taken 44037 times.
✓ Branch 1 taken 129604 times.
|
173641 | return is_temp_table(ci) ? ha_default_temp_handlerton(thd) |
| 227 | 173641 | : ha_default_handlerton(thd); | |
| 228 | } | ||
| 229 | |||
| 230 | 670931 | handlerton *requested_handlerton(THD *thd, const HA_CREATE_INFO &ci) { | |
| 231 |
2/2✓ Branch 0 taken 550677 times.
✓ Branch 1 taken 120254 times.
|
670931 | return is_engine_specified(ci) ? ci.db_type : default_handlerton(thd, ci); |
| 232 | } | ||
| 233 | |||
| 234 | struct Handlerton_pair { | ||
| 235 | handlerton *requested; | ||
| 236 | handlerton *alternate; | ||
| 237 | }; | ||
| 238 | |||
| 239 | using Viability_error_emitter = std::function<void(const char *engine_name)>; | ||
| 240 | using Viability_substitution_warning_emitter = std::function<void( | ||
| 241 | THD *, const char *requested_engine_name, | ||
| 242 | const char *substituted_engine_name, const char *table_name)>; | ||
| 243 | |||
| 244 | struct Viability { | ||
| 245 | bool value{true}; | ||
| 246 | Viability_error_emitter emit_error; | ||
| 247 | Viability_substitution_warning_emitter emit_substitution_warning; | ||
| 248 | 673015 | Viability() = default; | |
| 249 | 45 | Viability(Viability_error_emitter &&error_emitter, | |
| 250 | Viability_substitution_warning_emitter &&warning_emitter) | ||
| 251 | 45 | : value{false}, | |
| 252 | 45 | emit_error{std::move(error_emitter)}, | |
| 253 | 45 | emit_substitution_warning{std::move(warning_emitter)} { | |
| 254 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 45 times.
|
45 | assert(emit_error); |
| 255 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 45 times.
|
45 | assert(emit_substitution_warning); |
| 256 | 45 | } | |
| 257 | }; | ||
| 258 | |||
| 259 | 673061 | Viability get_viability(const handlerton &hton, const HA_CREATE_INFO &ci) { | |
| 260 |
1/2✓ Branch 0 taken 673063 times.
✗ Branch 1 not taken.
|
673061 | DBUG_TRACE; |
| 261 |
3/4✓ Branch 0 taken 673062 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39 times.
✓ Branch 3 taken 673023 times.
|
673063 | if (ha_is_externally_disabled(hton)) { |
| 262 | 27 | return {[](const char *en) { | |
| 263 | 27 | my_error(ER_DISABLED_STORAGE_ENGINE, MYF(0), en); | |
| 264 | 27 | }, | |
| 265 | 6 | [](THD *t, const char *ren, const char *sen, const char *tn) { | |
| 266 | 6 | push_warning_printf(t, Sql_condition::SL_WARNING, | |
| 267 | ER_DISABLED_STORAGE_ENGINE, | ||
| 268 | ER_THD(t, ER_DISABLED_STORAGE_ENGINE), ren); | ||
| 269 | 6 | push_warning_printf( | |
| 270 | t, Sql_condition::SL_WARNING, ER_WARN_USING_OTHER_HANDLER, | ||
| 271 | ER_THD(t, ER_WARN_USING_OTHER_HANDLER), sen, tn); | ||
| 272 | 39 | }}; | |
| 273 | } | ||
| 274 |
6/6✓ Branch 0 taken 51399 times.
✓ Branch 1 taken 621623 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 51393 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 673016 times.
|
724422 | if (is_temp_table(ci) && |
| 275 | 51399 | ha_check_storage_engine_flag(&hton, HTON_TEMPORARY_NOT_SUPPORTED)) { | |
| 276 | return { | ||
| 277 | 1 | [](const char *en) { | |
| 278 | 1 | my_error(ER_ILLEGAL_HA_CREATE_OPTION, MYF(0), en, "TEMPORARY"); | |
| 279 | 1 | }, | |
| 280 | 5 | [](THD *, const char *, const char *, | |
| 281 | 6 | const char *) { /* Nothing, no warning emitted in this case */ }}; | |
| 282 | } | ||
| 283 | 673016 | return {}; | |
| 284 | 673062 | } | |
| 285 | |||
| 286 | 672102 | handlerton *get_viable_handlerton_for_create_impl(THD *thd, | |
| 287 | const char *table_name, | ||
| 288 | const HA_CREATE_INFO &ci, | ||
| 289 | Handlerton_pair hp) { | ||
| 290 |
1/2✓ Branch 0 taken 672103 times.
✗ Branch 1 not taken.
|
672102 | DBUG_TRACE; |
| 291 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 672103 times.
|
672103 | assert(hp.requested != nullptr); |
| 292 |
1/2✓ Branch 0 taken 672104 times.
✗ Branch 1 not taken.
|
672103 | auto viability = get_viability(*hp.requested, ci); |
| 293 |
2/2✓ Branch 0 taken 672069 times.
✓ Branch 1 taken 35 times.
|
672104 | if (viability.value) { |
| 294 | 672069 | return hp.requested; | |
| 295 | } | ||
| 296 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
|
35 | assert(viability.emit_error); |
| 297 | |||
| 298 |
1/2✓ Branch 0 taken 35 times.
✗ Branch 1 not taken.
|
35 | const char *en = ha_resolve_storage_engine_name(hp.requested); |
| 299 |
2/2✓ Branch 0 taken 20 times.
✓ Branch 1 taken 15 times.
|
35 | if (hp.alternate == nullptr) { |
| 300 |
1/2✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
|
20 | viability.emit_error(en); |
| 301 | 20 | return nullptr; | |
| 302 | } | ||
| 303 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
15 | auto alt_viability = get_viability(*hp.alternate, ci); |
| 304 | |||
| 305 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
15 | const char *an = ha_resolve_storage_engine_name(hp.alternate); |
| 306 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 11 times.
|
15 | if (!alt_viability.value) { |
| 307 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | viability.emit_error(en); |
| 308 | 4 | return nullptr; | |
| 309 | } | ||
| 310 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
11 | viability.emit_substitution_warning(thd, en, an, table_name); |
| 311 | 11 | return hp.alternate; | |
| 312 | 672104 | } | |
| 313 | |||
| 314 | /** | ||
| 315 | Check if source is enabled AND NOT explicitly disabled (listed in the | ||
| 316 | disabled_storages_engines system variable. | ||
| 317 | |||
| 318 | If not; falls back to the default (tmp) storage engine if substitution | ||
| 319 | is allowed, unless this is also disabled. | ||
| 320 | |||
| 321 | Otherwise, if substitution does take place, ER_DISABLED_STORAGE_ENGINE and | ||
| 322 | ER_USING_OTHER_HANDLER are emitted as warnings. | ||
| 323 | |||
| 324 | For temporary tables the above also applies, and in addition the source | ||
| 325 | handlerton is checked to see if it supports temporary tables. | ||
| 326 | |||
| 327 | Note that this substitution is allowed even when no_substitution is ON, but | ||
| 328 | will fail if the default handlerton for temporary tables is disabled or does | ||
| 329 | not support temporary tables (unlikely). | ||
| 330 | |||
| 331 | @param thd Thread handler. | ||
| 332 | @param table_name Table name. | ||
| 333 | @param ci create info struct from parser. | ||
| 334 | @param source Handlerton requested by query. | ||
| 335 | |||
| 336 | @retval source if this is viable. | ||
| 337 | @retval The default hton if viable and engine substitution is allowed. | ||
| 338 | @retval The default temp hton if viable and a temporary table and source | ||
| 339 | does not support temporary tables. | ||
| 340 | @retval nullptr if error (source not viable and substitution | ||
| 341 | not possible). | ||
| 342 | */ | ||
| 343 | 1171 | handlerton *get_viable_handlerton_for_create_like(THD *thd, | |
| 344 | const char *table_name, | ||
| 345 | const HA_CREATE_INFO &ci, | ||
| 346 | handlerton *source) { | ||
| 347 | 1171 | return get_viable_handlerton_for_create_impl( | |
| 348 | thd, table_name, ci, | ||
| 349 |
2/2✓ Branch 0 taken 75 times.
✓ Branch 1 taken 1071 times.
|
2317 | {source, is_engine_substitution_allowed(thd) || is_temp_table(ci) |
| 350 |
2/2✓ Branch 0 taken 1146 times.
✓ Branch 1 taken 25 times.
|
2317 | ? default_handlerton(thd, ci) |
| 351 | 1171 | : nullptr}); | |
| 352 | } | ||
| 353 | |||
| 354 | /** | ||
| 355 | Does nothing (returns existing) unless ALTER changes the ENGINE. The | ||
| 356 | handlerton for the specified ENGINE is considered viable if it is enabled AND | ||
| 357 | NOT explicitly disabled (listed in the disabled_storages_engines system | ||
| 358 | variable). | ||
| 359 | |||
| 360 | If the specified handleton is not viable it falls back to existing if | ||
| 361 | substitution is allowed. existing is used without further checking, | ||
| 362 | and ER_UNKNOWN_STORAGE_ENGINE is emitted as warning. | ||
| 363 | |||
| 364 | @param thd Thread handler. | ||
| 365 | @param ci create info struct from parser. | ||
| 366 | @param existing Handlerton requested by query. | ||
| 367 | |||
| 368 | @retval existing if ENGINE is not specified or is the same as existing, or if | ||
| 369 | ENGINE is not viable and substitution is permitted. | ||
| 370 | @retval Handlerton of specified engine if this is viable. | ||
| 371 | @retval nullptr if error (specified engine not viable and substitution | ||
| 372 | not permitted). | ||
| 373 | */ | ||
| 374 | 943 | handlerton *get_viable_handlerton_for_alter(THD *thd, const HA_CREATE_INFO &ci, | |
| 375 | handlerton *existing) { | ||
| 376 |
1/2✓ Branch 0 taken 943 times.
✗ Branch 1 not taken.
|
943 | DBUG_TRACE; |
| 377 |
3/6✓ Branch 0 taken 943 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 943 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 943 times.
|
943 | if (!is_engine_specified(ci) || ci.db_type == existing) return existing; |
| 378 | |||
| 379 | Handlerton_pair hp = { | ||
| 380 |
2/2✓ Branch 0 taken 586 times.
✓ Branch 1 taken 357 times.
|
943 | ci.db_type, is_engine_substitution_allowed(thd) ? existing : nullptr}; |
| 381 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 943 times.
|
943 | assert(hp.requested != nullptr); |
| 382 |
1/2✓ Branch 0 taken 943 times.
✗ Branch 1 not taken.
|
943 | auto viability = get_viability(*hp.requested, ci); |
| 383 |
2/2✓ Branch 0 taken 937 times.
✓ Branch 1 taken 6 times.
|
943 | if (viability.value) { |
| 384 | 937 | return hp.requested; | |
| 385 | } | ||
| 386 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | const char *en = ha_resolve_storage_engine_name(hp.requested); |
| 387 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
|
6 | if (hp.alternate == nullptr) { |
| 388 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | viability.emit_error(en); |
| 389 | 4 | return nullptr; | |
| 390 | } | ||
| 391 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | push_warning_printf(thd, Sql_condition::SL_WARNING, ER_UNKNOWN_STORAGE_ENGINE, |
| 392 | ER_THD(thd, ER_UNKNOWN_STORAGE_ENGINE), en); | ||
| 393 | 2 | return hp.alternate; | |
| 394 | 943 | } | |
| 395 | } // namespace | ||
| 396 | |||
| 397 | /** | ||
| 398 | Checks if the handlerton for the specified ENGINE is enabled AND NOT | ||
| 399 | explicitly disabled (listed in the disabled_storages_engines system | ||
| 400 | variable). In the case of temporary tables the handlerton must also support | ||
| 401 | those to be viable. | ||
| 402 | |||
| 403 | When returning a handlerton different from the one specified | ||
| 404 | ER_DISABLED_STORAGE_ENGINE and ER_USING_OTHER_HANDLER are emitted as | ||
| 405 | warnings. | ||
| 406 | |||
| 407 | @param thd Thread handler. | ||
| 408 | @param table_name Table name. | ||
| 409 | @param ci create_info struct from parser. | ||
| 410 | |||
| 411 | @retval Handlerton for specified ENGINE if this is viable. | ||
| 412 | @retval The default (tmp) handlerton if viable and engine substitution is | ||
| 413 | allowed. | ||
| 414 | @retval nullptr if error (specified ENGINE not viable and substitution | ||
| 415 | not permitted). | ||
| 416 | */ | ||
| 417 | 670932 | handlerton *get_viable_handlerton_for_create(THD *thd, const char *table_name, | |
| 418 | const HA_CREATE_INFO &ci) { | ||
| 419 | 670931 | return get_viable_handlerton_for_create_impl( | |
| 420 | thd, table_name, ci, | ||
| 421 | 670932 | {requested_handlerton(thd, ci), | |
| 422 |
2/2✓ Branch 0 taken 53285 times.
✓ Branch 1 taken 497390 times.
|
1221609 | (is_engine_specified(ci) && is_engine_substitution_allowed(thd)) |
| 423 |
2/2✓ Branch 0 taken 550676 times.
✓ Branch 1 taken 120256 times.
|
1221607 | ? default_handlerton(thd, ci) |
| 424 | 670933 | : nullptr}); | |
| 425 | } | ||
| 426 | |||
| 427 | static bool check_if_keyname_exists(const char *name, KEY *start, KEY *end); | ||
| 428 | static const char *make_unique_key_name(const char *field_name, KEY *start, | ||
| 429 | KEY *end); | ||
| 430 | |||
| 431 | static const dd::Index *find_fk_supporting_key(handlerton *hton, | ||
| 432 | const dd::Table *table_def, | ||
| 433 | const dd::Foreign_key *fk); | ||
| 434 | |||
| 435 | static const dd::Index *find_fk_parent_key(handlerton *hton, | ||
| 436 | const dd::Index *supporting_key, | ||
| 437 | const dd::Table *parent_table_def, | ||
| 438 | const dd::Foreign_key *fk); | ||
| 439 | static int copy_data_between_tables( | ||
| 440 | THD *thd, PSI_stage_progress *psi, TABLE *from, TABLE *to, | ||
| 441 | List<Create_field> &create, ha_rows *copied, ha_rows *deleted, | ||
| 442 | Alter_info::enum_enable_or_disable keys_onoff, Alter_table_ctx *alter_ctx, | ||
| 443 | bool expand_fast_index_creation); | ||
| 444 | |||
| 445 | static bool prepare_blob_field(THD *thd, Create_field *sql_field, | ||
| 446 | bool convert_character_set); | ||
| 447 | static bool check_engine(THD *thd, const char *db_name, const char *table_name, | ||
| 448 | HA_CREATE_INFO *create_info, | ||
| 449 | const Alter_info *alter_info); | ||
| 450 | |||
| 451 | static bool prepare_set_field(THD *thd, Create_field *sql_field); | ||
| 452 | static bool prepare_enum_field(THD *thd, Create_field *sql_field); | ||
| 453 | |||
| 454 | static uint blob_length_by_type(enum_field_types type); | ||
| 455 | static const Create_field *get_field_by_index(Alter_info *alter_info, uint idx); | ||
| 456 | |||
| 457 | static bool generate_check_constraint_name(THD *thd, const char *table_name, | ||
| 458 | uint ordinal_number, | ||
| 459 | LEX_STRING &name, | ||
| 460 | bool skip_validation); | ||
| 461 | static bool push_check_constraint_mdl_request_to_list( | ||
| 462 | THD *thd, const char *db, const char *cc_name, | ||
| 463 | MDL_request_list &cc_mdl_request_list); | ||
| 464 | static bool prepare_check_constraints_for_create_like_table( | ||
| 465 | THD *thd, TABLE_LIST *src_table, TABLE_LIST *table, Alter_info *alter_info); | ||
| 466 | static bool prepare_check_constraints_for_alter(THD *thd, const TABLE *table, | ||
| 467 | Alter_info *alter_info, | ||
| 468 | Alter_table_ctx *alter_tbl_ctx); | ||
| 469 | static void set_check_constraints_alter_mode(dd::Table *table, | ||
| 470 | Alter_info *alter_info); | ||
| 471 | static void reset_check_constraints_alter_mode(dd::Table *table); | ||
| 472 | static bool adjust_check_constraint_names_for_old_table_version( | ||
| 473 | THD *thd, const char *old_table_db, dd::Table *old_table); | ||
| 474 | static bool is_any_check_constraints_evaluation_required( | ||
| 475 | const Alter_info *alter_info); | ||
| 476 | |||
| 477 | static bool check_if_field_used_by_generated_column_or_default( | ||
| 478 | TABLE *table, const Field *field, const Alter_info *alter_info); | ||
| 479 | |||
| 480 | /** | ||
| 481 | RAII class to control the atomic DDL commit on slave. | ||
| 482 | A slave context flag responsible to mark the DDL as committed is | ||
| 483 | raised and kept for the entirety of DDL commit block. | ||
| 484 | While DDL commits the slave info table won't take part | ||
| 485 | in its transaction. | ||
| 486 | */ | ||
| 487 | class Disable_slave_info_update_guard { | ||
| 488 | Relay_log_info *m_rli; | ||
| 489 | bool m_flag; | ||
| 490 | |||
| 491 | public: | ||
| 492 | 3 | Disable_slave_info_update_guard(THD *thd) | |
| 493 | 3 | : m_rli(thd->rli_slave), m_flag(false) { | |
| 494 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | if (!thd->slave_thread) { |
| 495 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | assert(!m_rli); |
| 496 | |||
| 497 | 3 | return; | |
| 498 | } | ||
| 499 | |||
| 500 | ✗ | assert(m_rli->current_event); | |
| 501 | |||
| 502 | ✗ | m_flag = static_cast<Query_log_event *>(thd->rli_slave->current_event) | |
| 503 | ✗ | ->has_ddl_committed; | |
| 504 | ✗ | static_cast<Query_log_event *>(m_rli->current_event)->has_ddl_committed = | |
| 505 | true; | ||
| 506 | } | ||
| 507 | |||
| 508 | 3 | ~Disable_slave_info_update_guard() { | |
| 509 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (m_rli) { |
| 510 | ✗ | static_cast<Query_log_event *>(m_rli->current_event)->has_ddl_committed = | |
| 511 | ✗ | m_flag; | |
| 512 | } | ||
| 513 | 3 | } | |
| 514 | }; | ||
| 515 | |||
| 516 | 172542 | static bool trans_intermediate_ddl_commit(THD *thd, bool error) { | |
| 517 | // Must be used for intermediate (but not final) DDL commits. | ||
| 518 |
1/2✓ Branch 0 taken 172542 times.
✗ Branch 1 not taken.
|
172542 | Implicit_substatement_state_guard substatement_guard(thd); |
| 519 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 172538 times.
|
172542 | if (error) { |
| 520 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | trans_rollback_stmt(thd); |
| 521 | // Full rollback in case we have THD::transaction_rollback_request. | ||
| 522 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | trans_rollback(thd); |
| 523 | 4 | return true; | |
| 524 | } | ||
| 525 |
4/8✓ Branch 0 taken 172538 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 172538 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 172538 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 172538 times.
|
172538 | return trans_commit_stmt(thd) || trans_commit(thd); |
| 526 | 172542 | } | |
| 527 | |||
| 528 | /** | ||
| 529 | @brief Helper function for explain_filename | ||
| 530 | @param thd Thread handle | ||
| 531 | @param to_p Explained name in system_charset_info | ||
| 532 | @param end_p End of the to_p buffer | ||
| 533 | @param name Name to be converted | ||
| 534 | @param name_len Length of the name, in bytes | ||
| 535 | */ | ||
| 536 | 32835 | static char *add_identifier(THD *thd, char *to_p, const char *end_p, | |
| 537 | const char *name, size_t name_len) { | ||
| 538 | size_t res; | ||
| 539 | uint errors; | ||
| 540 | const char *conv_name; | ||
| 541 | char tmp_name[FN_REFLEN]; | ||
| 542 | char conv_string[FN_REFLEN]; | ||
| 543 | int quote; | ||
| 544 | |||
| 545 |
1/2✓ Branch 0 taken 32835 times.
✗ Branch 1 not taken.
|
32835 | DBUG_TRACE; |
| 546 |
2/2✓ Branch 0 taken 31201 times.
✓ Branch 1 taken 1634 times.
|
32835 | if (!name[name_len]) |
| 547 | 31201 | conv_name = name; | |
| 548 | else { | ||
| 549 | 1634 | my_stpnmov(tmp_name, name, name_len); | |
| 550 | 1634 | tmp_name[name_len] = 0; | |
| 551 | 1634 | conv_name = tmp_name; | |
| 552 | } | ||
| 553 |
1/2✓ Branch 0 taken 32835 times.
✗ Branch 1 not taken.
|
32835 | res = strconvert(&my_charset_filename, conv_name, system_charset_info, |
| 554 | conv_string, FN_REFLEN, &errors); | ||
| 555 |
3/4✓ Branch 0 taken 32835 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 75 times.
✓ Branch 3 taken 32760 times.
|
32835 | if (!res || errors) { |
| 556 |
3/8✓ Branch 0 taken 75 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 75 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 75 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
75 | DBUG_PRINT("error", ("strconvert of '%s' failed with %u (errors: %u)", |
| 557 | conv_name, static_cast<uint>(res), errors)); | ||
| 558 | 75 | conv_name = name; | |
| 559 | } else { | ||
| 560 |
3/8✓ Branch 0 taken 32760 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 32760 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 32760 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
32760 | DBUG_PRINT("info", ("conv '%s' -> '%s'", conv_name, conv_string)); |
| 561 | 32760 | conv_name = conv_string; | |
| 562 | } | ||
| 563 | |||
| 564 |
3/4✓ Branch 0 taken 26234 times.
✓ Branch 1 taken 6601 times.
✓ Branch 2 taken 26234 times.
✗ Branch 3 not taken.
|
32835 | quote = thd ? get_quote_char_for_identifier(thd, conv_name, res - 1) : '`'; |
| 565 | |||
| 566 |
2/4✓ Branch 0 taken 32835 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 32835 times.
✗ Branch 3 not taken.
|
32835 | if (quote != EOF && (end_p - to_p > 2)) { |
| 567 | 32835 | *(to_p++) = (char)quote; | |
| 568 |
3/4✓ Branch 0 taken 212717 times.
✓ Branch 1 taken 32835 times.
✓ Branch 2 taken 212717 times.
✗ Branch 3 not taken.
|
245552 | while (*conv_name && (end_p - to_p - 1) > 0) { |
| 569 |
1/2✓ Branch 0 taken 212717 times.
✗ Branch 1 not taken.
|
212717 | uint length = my_mbcharlen(system_charset_info, *conv_name); |
| 570 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 212711 times.
|
212717 | if (!length) length = 1; |
| 571 |
3/4✓ Branch 0 taken 212717 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 212705 times.
|
212717 | if (length == 1 && *conv_name == (char)quote) { |
| 572 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | if ((end_p - to_p) < 3) break; |
| 573 | 12 | *(to_p++) = (char)quote; | |
| 574 | 12 | *(to_p++) = *(conv_name++); | |
| 575 |
1/2✓ Branch 0 taken 212705 times.
✗ Branch 1 not taken.
|
212705 | } else if (((long)length) < (end_p - to_p)) { |
| 576 | 212705 | to_p = my_stpnmov(to_p, conv_name, length); | |
| 577 | 212705 | conv_name += length; | |
| 578 | } else | ||
| 579 | ✗ | break; /* string already filled */ | |
| 580 | } | ||
| 581 |
1/2✓ Branch 0 taken 32835 times.
✗ Branch 1 not taken.
|
32835 | if (end_p > to_p) { |
| 582 | 32835 | *(to_p++) = (char)quote; | |
| 583 |
1/2✓ Branch 0 taken 32835 times.
✗ Branch 1 not taken.
|
32835 | if (end_p > to_p) |
| 584 | 32835 | *to_p = 0; /* terminate by NUL, but do not include it in the count */ | |
| 585 | } | ||
| 586 | 32835 | } else | |
| 587 | ✗ | to_p = my_stpnmov(to_p, conv_name, end_p - to_p); | |
| 588 | 32835 | return to_p; | |
| 589 | 32835 | } | |
| 590 | |||
| 591 | /** | ||
| 592 | @brief Explain a path name by split it to database, table etc. | ||
| 593 | |||
| 594 | @details Break down the path name to its logic parts | ||
| 595 | (database, table, partition, subpartition). | ||
| 596 | filename_to_tablename cannot be used on partitions, due to the @#P@# part. | ||
| 597 | There can be up to 6 '#', @#P@# for partition, @#SP@# for subpartition | ||
| 598 | and @#TMP@# or @#REN@# for temporary or renamed partitions. | ||
| 599 | This should be used when something should be presented to a user in a | ||
| 600 | diagnostic, error etc. when it would be useful to know what a particular | ||
| 601 | file [and directory] means. Such as SHOW ENGINE STATUS, error messages etc. | ||
| 602 | |||
| 603 | Examples: | ||
| 604 | |||
| 605 | t1#P#p1 table t1 partition p1 | ||
| 606 | t1#P#p1#SP#sp1 table t1 partition p1 subpartition sp1 | ||
| 607 | t1#P#p1#SP#sp1#TMP# table t1 partition p1 subpartition sp1 temporary | ||
| 608 | t1#P#p1#SP#sp1#REN# table t1 partition p1 subpartition sp1 renamed | ||
| 609 | |||
| 610 | @param thd Thread handle | ||
| 611 | @param from Path name in my_charset_filename | ||
| 612 | Null terminated in my_charset_filename, normalized | ||
| 613 | to use '/' as directory separation character. | ||
| 614 | @param to Explained name in system_charset_info | ||
| 615 | @param to_length Size of to buffer | ||
| 616 | @param explain_mode Requested output format. | ||
| 617 | EXPLAIN_ALL_VERBOSE -> | ||
| 618 | [Database `db`, ]Table `tbl`[,[ Temporary| Renamed] | ||
| 619 | Partition `p` [, Subpartition `sp`]] | ||
| 620 | EXPLAIN_PARTITIONS_VERBOSE -> `db`.`tbl` | ||
| 621 | [[ Temporary| Renamed] Partition `p` | ||
| 622 | [, Subpartition `sp`]] | ||
| 623 | EXPLAIN_PARTITIONS_AS_COMMENT -> `db`.`tbl` |* | ||
| 624 | [,[ Temporary| Renamed] Partition `p` | ||
| 625 | [, Subpartition `sp`]] *| | ||
| 626 | (| is really a /, and it is all in one line) | ||
| 627 | |||
| 628 | @retval Length of returned string | ||
| 629 | */ | ||
| 630 | |||
| 631 | 31210 | size_t explain_filename(THD *thd, const char *from, char *to, size_t to_length, | |
| 632 | enum_explain_filename_mode explain_mode) { | ||
| 633 | 31210 | char *to_p = to; | |
| 634 | 31210 | char *end_p = to_p + to_length; | |
| 635 | 31210 | const char *db_name = nullptr; | |
| 636 | 31210 | size_t db_name_len = 0; | |
| 637 | const char *table_name; | ||
| 638 | 31210 | size_t table_name_len = 0; | |
| 639 | 31210 | const char *part_name = nullptr; | |
| 640 | 31210 | size_t part_name_len = 0; | |
| 641 | 31210 | const char *subpart_name = nullptr; | |
| 642 | 31210 | size_t subpart_name_len = 0; | |
| 643 | 31210 | enum enum_part_name_type { NORMAL, TEMP, RENAMED } part_type = NORMAL; | |
| 644 | |||
| 645 | const char *tmp_p; | ||
| 646 |
1/2✓ Branch 0 taken 31210 times.
✗ Branch 1 not taken.
|
31210 | DBUG_TRACE; |
| 647 |
3/8✓ Branch 0 taken 31210 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31210 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 31210 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
31210 | DBUG_PRINT("enter", ("from '%s'", from)); |
| 648 | 31210 | tmp_p = from; | |
| 649 | 31210 | table_name = from; | |
| 650 | /* | ||
| 651 | If '/' then take last directory part as database. | ||
| 652 | '/' is the directory separator, not FN_LIB_CHAR | ||
| 653 | */ | ||
| 654 |
2/2✓ Branch 0 taken 60 times.
✓ Branch 1 taken 31210 times.
|
31270 | while ((tmp_p = strchr(tmp_p, '/'))) { |
| 655 | 60 | db_name = table_name; | |
| 656 | /* calculate the length */ | ||
| 657 | 60 | db_name_len = tmp_p - db_name; | |
| 658 | 60 | tmp_p++; | |
| 659 | 60 | table_name = tmp_p; | |
| 660 | } | ||
| 661 | 31210 | tmp_p = table_name; | |
| 662 | /* Look if there are partition tokens in the table name. */ | ||
| 663 | 31210 | while ((tmp_p = strchr(tmp_p, '#'))) { | |
| 664 | 1642 | tmp_p++; | |
| 665 |
5/5✓ Branch 0 taken 1258 times.
✓ Branch 1 taken 354 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 9 times.
|
1642 | switch (tmp_p[0]) { |
| 666 | 1258 | case 'P': | |
| 667 | case 'p': | ||
| 668 |
2/2✓ Branch 0 taken 1255 times.
✓ Branch 1 taken 3 times.
|
1258 | if (tmp_p[1] == '#') { |
| 669 | 1255 | part_name = tmp_p + 2; | |
| 670 | 1255 | tmp_p += 2; | |
| 671 | } | ||
| 672 | 1258 | break; | |
| 673 | 354 | case 'S': | |
| 674 | case 's': | ||
| 675 |
5/6✓ Branch 0 taken 329 times.
✓ Branch 1 taken 25 times.
✓ Branch 2 taken 288 times.
✓ Branch 3 taken 41 times.
✓ Branch 4 taken 313 times.
✗ Branch 5 not taken.
|
354 | if ((tmp_p[1] == 'P' || tmp_p[1] == 'p') && tmp_p[2] == '#') { |
| 676 | 313 | part_name_len = tmp_p - part_name - 1; | |
| 677 | 313 | subpart_name = tmp_p + 3; | |
| 678 | 313 | tmp_p += 3; | |
| 679 | } | ||
| 680 | 354 | break; | |
| 681 | 15 | case 'T': | |
| 682 | case 't': | ||
| 683 |
3/4✓ Branch 0 taken 6 times.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
|
15 | if ((tmp_p[1] == 'M' || tmp_p[1] == 'm') && |
| 684 |
2/6✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
|
9 | (tmp_p[2] == 'P' || tmp_p[2] == 'p') && tmp_p[3] == '#' && |
| 685 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
9 | !tmp_p[4]) { |
| 686 | 9 | part_type = TEMP; | |
| 687 | 9 | tmp_p += 4; | |
| 688 | } | ||
| 689 | 15 | break; | |
| 690 | 6 | case 'R': | |
| 691 | case 'r': | ||
| 692 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
6 | if ((tmp_p[1] == 'E' || tmp_p[1] == 'e') && |
| 693 |
2/6✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
|
6 | (tmp_p[2] == 'N' || tmp_p[2] == 'n') && tmp_p[3] == '#' && |
| 694 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | !tmp_p[4]) { |
| 695 | 6 | part_type = RENAMED; | |
| 696 | 6 | tmp_p += 4; | |
| 697 | } | ||
| 698 | 6 | break; | |
| 699 |
2/2✓ Branch 0 taken 1642 times.
✓ Branch 1 taken 31210 times.
|
32852 | default: |
| 700 | /* Not partition name part. */ | ||
| 701 | ; | ||
| 702 | } | ||
| 703 | } | ||
| 704 |
2/2✓ Branch 0 taken 1255 times.
✓ Branch 1 taken 29955 times.
|
31210 | if (part_name) { |
| 705 | 1255 | table_name_len = part_name - table_name - 3; | |
| 706 |
2/2✓ Branch 0 taken 310 times.
✓ Branch 1 taken 945 times.
|
1255 | if (subpart_name) |
| 707 | 310 | subpart_name_len = strlen(subpart_name); | |
| 708 | else | ||
| 709 | 945 | part_name_len = strlen(part_name); | |
| 710 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1246 times.
|
1255 | if (part_type != NORMAL) { |
| 711 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
9 | if (subpart_name) |
| 712 | 9 | subpart_name_len -= 5; | |
| 713 | else | ||
| 714 | ✗ | part_name_len -= 5; | |
| 715 | } | ||
| 716 | } else | ||
| 717 | 29955 | table_name_len = strlen(table_name); | |
| 718 |
2/2✓ Branch 0 taken 60 times.
✓ Branch 1 taken 31150 times.
|
31210 | if (db_name) { |
| 719 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 42 times.
|
60 | if (explain_mode == EXPLAIN_ALL_VERBOSE) { |
| 720 |
1/4✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | to_p = my_stpncpy(to_p, ER_THD_OR_DEFAULT(thd, ER_DATABASE_NAME), |
| 721 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | end_p - to_p); |
| 722 | 18 | *(to_p++) = ' '; | |
| 723 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | to_p = add_identifier(thd, to_p, end_p, db_name, db_name_len); |
| 724 | 18 | to_p = my_stpncpy(to_p, ", ", end_p - to_p); | |
| 725 | } else { | ||
| 726 |
1/2✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
|
42 | to_p = add_identifier(thd, to_p, end_p, db_name, db_name_len); |
| 727 | 42 | to_p = my_stpncpy(to_p, ".", end_p - to_p); | |
| 728 | } | ||
| 729 | } | ||
| 730 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 31192 times.
|
31210 | if (explain_mode == EXPLAIN_ALL_VERBOSE) { |
| 731 | to_p = | ||
| 732 |
2/6✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
|
18 | my_stpncpy(to_p, ER_THD_OR_DEFAULT(thd, ER_TABLE_NAME), end_p - to_p); |
| 733 | 18 | *(to_p++) = ' '; | |
| 734 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | to_p = add_identifier(thd, to_p, end_p, table_name, table_name_len); |
| 735 | } else | ||
| 736 |
1/2✓ Branch 0 taken 31192 times.
✗ Branch 1 not taken.
|
31192 | to_p = add_identifier(thd, to_p, end_p, table_name, table_name_len); |
| 737 |
2/2✓ Branch 0 taken 1255 times.
✓ Branch 1 taken 29955 times.
|
31210 | if (part_name) { |
| 738 |
2/2✓ Branch 0 taken 1252 times.
✓ Branch 1 taken 3 times.
|
1255 | if (explain_mode == EXPLAIN_PARTITIONS_AS_COMMENT) |
| 739 | 1252 | to_p = my_stpncpy(to_p, " /* ", end_p - to_p); | |
| 740 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | else if (explain_mode == EXPLAIN_PARTITIONS_VERBOSE) |
| 741 | ✗ | to_p = my_stpncpy(to_p, " ", end_p - to_p); | |
| 742 | else | ||
| 743 | 3 | to_p = my_stpncpy(to_p, ", ", end_p - to_p); | |
| 744 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1246 times.
|
1255 | if (part_type != NORMAL) { |
| 745 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 3 times.
|
9 | if (part_type == TEMP) |
| 746 |
1/4✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
|
6 | to_p = my_stpncpy(to_p, ER_THD_OR_DEFAULT(thd, ER_TEMPORARY_NAME), |
| 747 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | end_p - to_p); |
| 748 | else | ||
| 749 |
1/4✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | to_p = my_stpncpy(to_p, ER_THD_OR_DEFAULT(thd, ER_RENAMED_NAME), |
| 750 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | end_p - to_p); |
| 751 | 9 | to_p = my_stpncpy(to_p, " ", end_p - to_p); | |
| 752 | } | ||
| 753 |
2/4✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1218 times.
✗ Branch 3 not taken.
|
1255 | to_p = my_stpncpy(to_p, ER_THD_OR_DEFAULT(thd, ER_PARTITION_NAME), |
| 754 |
2/2✓ Branch 0 taken 37 times.
✓ Branch 1 taken 1218 times.
|
1255 | end_p - to_p); |
| 755 | 1255 | *(to_p++) = ' '; | |
| 756 |
1/2✓ Branch 0 taken 1255 times.
✗ Branch 1 not taken.
|
1255 | to_p = add_identifier(thd, to_p, end_p, part_name, part_name_len); |
| 757 |
2/2✓ Branch 0 taken 310 times.
✓ Branch 1 taken 945 times.
|
1255 | if (subpart_name) { |
| 758 | 310 | to_p = my_stpncpy(to_p, ", ", end_p - to_p); | |
| 759 |
1/4✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 310 times.
✗ Branch 3 not taken.
|
310 | to_p = my_stpncpy(to_p, ER_THD_OR_DEFAULT(thd, ER_SUBPARTITION_NAME), |
| 760 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 310 times.
|
310 | end_p - to_p); |
| 761 | 310 | *(to_p++) = ' '; | |
| 762 |
1/2✓ Branch 0 taken 310 times.
✗ Branch 1 not taken.
|
310 | to_p = add_identifier(thd, to_p, end_p, subpart_name, subpart_name_len); |
| 763 | } | ||
| 764 |
2/2✓ Branch 0 taken 1252 times.
✓ Branch 1 taken 3 times.
|
1255 | if (explain_mode == EXPLAIN_PARTITIONS_AS_COMMENT) |
| 765 | 1252 | to_p = my_stpncpy(to_p, " */", end_p - to_p); | |
| 766 | } | ||
| 767 |
3/8✓ Branch 0 taken 31210 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31210 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 31210 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
31210 | DBUG_PRINT("exit", ("to '%s'", to)); |
| 768 | 31210 | return static_cast<size_t>(to_p - to); | |
| 769 | 31210 | } | |
| 770 | |||
| 771 | /* | ||
| 772 | Translate a file name to a table name (WL #1324). | ||
| 773 | |||
| 774 | SYNOPSIS | ||
| 775 | filename_to_tablename() | ||
| 776 | from The file name in my_charset_filename. | ||
| 777 | to OUT The table name in system_charset_info. | ||
| 778 | to_length The size of the table name buffer. | ||
| 779 | |||
| 780 | RETURN | ||
| 781 | Table name length. | ||
| 782 | */ | ||
| 783 | |||
| 784 | 39338093 | size_t filename_to_tablename(const char *from, char *to, size_t to_length, | |
| 785 | bool stay_quiet) { | ||
| 786 | uint errors; | ||
| 787 | size_t res; | ||
| 788 |
1/2✓ Branch 0 taken 39338201 times.
✗ Branch 1 not taken.
|
39338093 | DBUG_TRACE; |
| 789 |
5/8✓ Branch 0 taken 39338189 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39338155 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 208 times.
✓ Branch 5 taken 39337947 times.
✓ Branch 6 taken 208 times.
✗ Branch 7 not taken.
|
39338201 | DBUG_PRINT("enter", ("from '%s'", from)); |
| 790 | |||
| 791 |
2/2✓ Branch 0 taken 36577232 times.
✓ Branch 1 taken 2760923 times.
|
39338155 | if (strlen(from) >= tmp_file_prefix_length && |
| 792 |
2/2✓ Branch 0 taken 654820 times.
✓ Branch 1 taken 35922412 times.
|
36577232 | !memcmp(from, tmp_file_prefix, tmp_file_prefix_length)) { |
| 793 | /* Temporary table name. */ | ||
| 794 | 654820 | res = (my_stpnmov(to, from, to_length) - to); | |
| 795 | } else { | ||
| 796 |
1/2✓ Branch 0 taken 38683368 times.
✗ Branch 1 not taken.
|
38683335 | res = strconvert(&my_charset_filename, from, system_charset_info, to, |
| 797 | to_length, &errors); | ||
| 798 |
2/2✓ Branch 0 taken 436072 times.
✓ Branch 1 taken 38247296 times.
|
38683368 | if (errors) // Old 5.0 name |
| 799 | { | ||
| 800 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 436072 times.
|
436072 | if (!stay_quiet) { |
| 801 | ✗ | LogErr(ERROR_LEVEL, ER_INVALID_OR_OLD_TABLE_OR_DB_NAME, from); | |
| 802 | } | ||
| 803 | /* | ||
| 804 | TODO: add a stored procedure for fix table and database names, | ||
| 805 | and mention its name in error log. | ||
| 806 | */ | ||
| 807 | } | ||
| 808 | } | ||
| 809 | |||
| 810 |
5/8✓ Branch 0 taken 39338132 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39338151 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 204 times.
✓ Branch 5 taken 39337947 times.
✓ Branch 6 taken 204 times.
✗ Branch 7 not taken.
|
39338188 | DBUG_PRINT("exit", ("to '%s'", to)); |
| 811 | 39338203 | return res; | |
| 812 | 39338151 | } | |
| 813 | |||
| 814 | /* | ||
| 815 | Translate a table name to a file name (WL #1324). | ||
| 816 | |||
| 817 | SYNOPSIS | ||
| 818 | tablename_to_filename() | ||
| 819 | from The table name in system_charset_info. | ||
| 820 | to OUT The file name in my_charset_filename. | ||
| 821 | to_length The size of the file name buffer. | ||
| 822 | |||
| 823 | RETURN | ||
| 824 | File name length. | ||
| 825 | */ | ||
| 826 | |||
| 827 | 9896742 | size_t tablename_to_filename(const char *from, char *to, size_t to_length) { | |
| 828 | uint errors; | ||
| 829 | size_t length; | ||
| 830 |
1/2✓ Branch 0 taken 9896751 times.
✗ Branch 1 not taken.
|
9896742 | DBUG_TRACE; |
| 831 |
5/8✓ Branch 0 taken 9896750 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9896751 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 319 times.
✓ Branch 5 taken 9896432 times.
✓ Branch 6 taken 319 times.
✗ Branch 7 not taken.
|
9896751 | DBUG_PRINT("enter", ("from '%s'", from)); |
| 832 | |||
| 833 |
1/2✓ Branch 0 taken 9896749 times.
✗ Branch 1 not taken.
|
9896751 | length = strconvert(system_charset_info, from, &my_charset_filename, to, |
| 834 | to_length, &errors); | ||
| 835 |
6/8✓ Branch 0 taken 9896748 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 9896738 times.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 10 times.
✓ Branch 7 taken 9896738 times.
|
9896749 | if (check_if_legal_tablename(to) && length + 4 < to_length) { |
| 836 | 10 | memcpy(to + length, "@@@", 4); | |
| 837 | 10 | length += 3; | |
| 838 | } | ||
| 839 |
5/8✓ Branch 0 taken 9896750 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9896751 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 313 times.
✓ Branch 5 taken 9896438 times.
✓ Branch 6 taken 313 times.
✗ Branch 7 not taken.
|
9896748 | DBUG_PRINT("exit", ("to '%s'", to)); |
| 840 | 9896751 | return length; | |
| 841 | 9896751 | } | |
| 842 | |||
| 843 | /* | ||
| 844 | @brief Creates path to a file: mysql_data_dir/db/table.ext | ||
| 845 | |||
| 846 | @param buff Where to write result in my_charset_filename. | ||
| 847 | This may be the same as table_name. | ||
| 848 | @param bufflen buff size | ||
| 849 | @param db Database name in system_charset_info. | ||
| 850 | @param table_name Table name in system_charset_info. | ||
| 851 | @param ext File extension. | ||
| 852 | @param flags FN_FROM_IS_TMP or FN_TO_IS_TMP or FN_IS_TMP | ||
| 853 | table_name is temporary, do not change. | ||
| 854 | @param was_truncated points to location that will be | ||
| 855 | set to true if path was truncated, | ||
| 856 | to false otherwise. | ||
| 857 | |||
| 858 | @note | ||
| 859 | Uses database and table name, and extension to create | ||
| 860 | a file name in mysql_data_dir. Database and table | ||
| 861 | names are converted from system_charset_info into "fscs". | ||
| 862 | Unless flags indicate a temporary table name. | ||
| 863 | 'db' is always converted. | ||
| 864 | 'ext' is not converted. | ||
| 865 | |||
| 866 | The conversion suppression is required for ALTER TABLE. This | ||
| 867 | statement creates intermediate tables. These are regular | ||
| 868 | (non-temporary) tables with a temporary name. Their path names must | ||
| 869 | be derivable from the table name. So we cannot use | ||
| 870 | build_tmptable_filename() for them. | ||
| 871 | |||
| 872 | @return | ||
| 873 | path length | ||
| 874 | */ | ||
| 875 | |||
| 876 | 4921885 | size_t build_table_filename(char *buff, size_t bufflen, const char *db, | |
| 877 | const char *table_name, const char *ext, uint flags, | ||
| 878 | bool *was_truncated) { | ||
| 879 | char tbbuff[FN_REFLEN], dbbuff[FN_REFLEN]; | ||
| 880 | size_t tab_len, db_len; | ||
| 881 |
1/2✓ Branch 0 taken 4921892 times.
✗ Branch 1 not taken.
|
4921885 | DBUG_TRACE; |
| 882 |
5/8✓ Branch 0 taken 4921892 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4921892 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 160 times.
✓ Branch 5 taken 4921732 times.
✓ Branch 6 taken 160 times.
✗ Branch 7 not taken.
|
4921892 | DBUG_PRINT("enter", ("db: '%s' table_name: '%s' ext: '%s' flags: %x", db, |
| 883 | table_name, ext, flags)); | ||
| 884 | |||
| 885 |
2/2✓ Branch 0 taken 146593 times.
✓ Branch 1 taken 4775295 times.
|
4921888 | if (flags & FN_IS_TMP) // FN_FROM_IS_TMP | FN_TO_IS_TMP |
| 886 | 146593 | tab_len = my_stpnmov(tbbuff, table_name, sizeof(tbbuff)) - tbbuff; | |
| 887 | else | ||
| 888 |
1/2✓ Branch 0 taken 4775300 times.
✗ Branch 1 not taken.
|
4775295 | tab_len = tablename_to_filename(table_name, tbbuff, sizeof(tbbuff)); |
| 889 | |||
| 890 |
1/2✓ Branch 0 taken 4921893 times.
✗ Branch 1 not taken.
|
4921893 | db_len = tablename_to_filename(db, dbbuff, sizeof(dbbuff)); |
| 891 | |||
| 892 | 4921893 | char *end = buff + bufflen; | |
| 893 | /* Don't add FN_ROOTDIR if mysql_data_home already includes it */ | ||
| 894 | 4921893 | char *pos = my_stpnmov(buff, mysql_data_home, bufflen); | |
| 895 | 4921890 | size_t rootdir_len = strlen(FN_ROOTDIR); | |
| 896 |
1/2✓ Branch 0 taken 4921891 times.
✗ Branch 1 not taken.
|
4921890 | if (pos - rootdir_len >= buff && |
| 897 |
2/2✓ Branch 0 taken 4921885 times.
✓ Branch 1 taken 6 times.
|
4921891 | memcmp(pos - rootdir_len, FN_ROOTDIR, rootdir_len) != 0) |
| 898 | 4921885 | pos = my_stpnmov(pos, FN_ROOTDIR, end - pos); | |
| 899 | else | ||
| 900 | 5 | rootdir_len = 0; | |
| 901 |
1/2✓ Branch 0 taken 4921888 times.
✗ Branch 1 not taken.
|
4921896 | pos = strxnmov(pos, end - pos, dbbuff, FN_ROOTDIR, NullS); |
| 902 |
1/2✓ Branch 0 taken 4921886 times.
✗ Branch 1 not taken.
|
4921888 | pos = strxnmov(pos, end - pos, tbbuff, ext, NullS); |
| 903 | |||
| 904 | /** | ||
| 905 | Mark OUT param if path gets truncated. | ||
| 906 | Most of functions which invoke this function are sure that the | ||
| 907 | path will not be truncated. In case some functions are not sure, | ||
| 908 | we can use 'was_truncated' OUTPARAM | ||
| 909 | */ | ||
| 910 | 4921886 | *was_truncated = false; | |
| 911 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4921884 times.
|
4921886 | if (pos == end && (bufflen < mysql_data_home_len + rootdir_len + db_len + |
| 912 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | strlen(FN_ROOTDIR) + tab_len + strlen(ext))) |
| 913 | 1 | *was_truncated = true; | |
| 914 | |||
| 915 |
5/8✓ Branch 0 taken 4921893 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4921893 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 157 times.
✓ Branch 5 taken 4921736 times.
✓ Branch 6 taken 157 times.
✗ Branch 7 not taken.
|
4921886 | DBUG_PRINT("exit", ("buff: '%s'", buff)); |
| 916 | 4921892 | return pos - buff; | |
| 917 | 4921893 | } | |
| 918 | |||
| 919 | /** | ||
| 920 | Create path to a temporary table, like mysql_tmpdir/@#sql1234_12_1 | ||
| 921 | (i.e. to its .FRM file but without an extension). | ||
| 922 | |||
| 923 | @param thd The thread handle. | ||
| 924 | @param buff Where to write result in my_charset_filename. | ||
| 925 | @param bufflen buff size | ||
| 926 | |||
| 927 | @note | ||
| 928 | Uses current_pid, thread_id, and tmp_table counter to create | ||
| 929 | a file name in mysql_tmpdir. | ||
| 930 | |||
| 931 | @return Path length. | ||
| 932 | */ | ||
| 933 | |||
| 934 | 52574 | size_t build_tmptable_filename(THD *thd, char *buff, size_t bufflen) { | |
| 935 |
1/2✓ Branch 0 taken 52574 times.
✗ Branch 1 not taken.
|
52574 | DBUG_TRACE; |
| 936 | |||
| 937 |
1/2✓ Branch 0 taken 52574 times.
✗ Branch 1 not taken.
|
52574 | char *p = my_stpnmov(buff, mysql_tmpdir, bufflen); |
| 938 | assert(sizeof(my_thread_id) == 4); | ||
| 939 | 105148 | snprintf(p, bufflen - (p - buff), "/%s%lx_%x_%x", tmp_file_prefix, | |
| 940 | 52574 | current_pid, thd->thread_id(), thd->tmp_table++); | |
| 941 | |||
| 942 |
2/2✓ Branch 0 taken 244 times.
✓ Branch 1 taken 52330 times.
|
52574 | if (lower_case_table_names) { |
| 943 | /* Convert all except tmpdir to lower case */ | ||
| 944 |
1/2✓ Branch 0 taken 244 times.
✗ Branch 1 not taken.
|
244 | my_casedn_str(files_charset_info, p); |
| 945 | } | ||
| 946 | |||
| 947 |
1/2✓ Branch 0 taken 52573 times.
✗ Branch 1 not taken.
|
52574 | size_t length = unpack_filename(buff, buff); |
| 948 |
3/8✓ Branch 0 taken 52574 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 52574 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 52574 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
52573 | DBUG_PRINT("exit", ("buff: '%s'", buff)); |
| 949 | 52574 | return length; | |
| 950 | 52574 | } | |
| 951 | |||
| 952 | /** | ||
| 953 | Create a dd::Table-object specifying the temporary table | ||
| 954 | definition, but do not put it into the Data Dictionary. The created | ||
| 955 | dd::Table-instance is returned via tmp_table_def out-parameter. | ||
| 956 | The temporary table is also created in the storage engine, depending | ||
| 957 | on the 'no_ha_table' argument. | ||
| 958 | |||
| 959 | @param thd Thread handler | ||
| 960 | @param path Name of file (including database) | ||
| 961 | @param sch_obj Schema. | ||
| 962 | @param db Schema name. | ||
| 963 | Cannot use dd::Schema::name() directly due to LCTN. | ||
| 964 | @param table_name Table name | ||
| 965 | @param create_info create info parameters | ||
| 966 | @param create_fields Fields to create | ||
| 967 | @param keys number of keys to create | ||
| 968 | @param key_info Keys to create | ||
| 969 | @param keys_onoff Enable or disable keys. | ||
| 970 | @param check_cons_spec List of check constraint specification. | ||
| 971 | @param file Handler to use | ||
| 972 | @param no_ha_table Indicates that only definitions needs to be created | ||
| 973 | and not a table in the storage engine. | ||
| 974 | @param[out] binlog_to_trx_cache | ||
| 975 | Which binlog cache should be used? | ||
| 976 | If true => trx cache | ||
| 977 | If false => stmt cache | ||
| 978 | @param[out] tmp_table_def Data-dictionary object for temporary table | ||
| 979 | which was created. Is not set if no_ha_table | ||
| 980 | was false. | ||
| 981 | |||
| 982 | @retval false ok | ||
| 983 | @retval true error | ||
| 984 | */ | ||
| 985 | |||
| 986 | 52459 | static bool rea_create_tmp_table( | |
| 987 | THD *thd, const char *path, const dd::Schema &sch_obj, const char *db, | ||
| 988 | const char *table_name, HA_CREATE_INFO *create_info, | ||
| 989 | List<Create_field> &create_fields, uint keys, KEY *key_info, | ||
| 990 | Alter_info::enum_enable_or_disable keys_onoff, | ||
| 991 | const Sql_check_constraint_spec_list *check_cons_spec, handler *file, | ||
| 992 | bool no_ha_table, bool *binlog_to_trx_cache, | ||
| 993 | std::unique_ptr<dd::Table> *tmp_table_def) { | ||
| 994 |
1/2✓ Branch 0 taken 52460 times.
✗ Branch 1 not taken.
|
52459 | DBUG_TRACE; |
| 995 | |||
| 996 | std::unique_ptr<dd::Table> tmp_table_ptr = | ||
| 997 | dd::create_tmp_table(thd, sch_obj, table_name, create_info, create_fields, | ||
| 998 |
2/4✓ Branch 0 taken 52460 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 52460 times.
✗ Branch 3 not taken.
|
52460 | key_info, keys, keys_onoff, check_cons_spec, file); |
| 999 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 52457 times.
|
52460 | if (!tmp_table_ptr) return true; |
| 1000 | |||
| 1001 |
2/2✓ Branch 0 taken 1151 times.
✓ Branch 1 taken 51306 times.
|
52457 | if (no_ha_table) { |
| 1002 | 1151 | *tmp_table_def = std::move(tmp_table_ptr); | |
| 1003 | 1151 | return false; | |
| 1004 | } | ||
| 1005 | |||
| 1006 | // Create the table in the storage engine. | ||
| 1007 |
3/4✓ Branch 0 taken 51304 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 108 times.
✓ Branch 3 taken 51196 times.
|
51306 | if (ha_create_table(thd, path, db, table_name, create_info, &create_fields, |
| 1008 | false, false, tmp_table_ptr.get())) { | ||
| 1009 | 108 | return true; | |
| 1010 | } | ||
| 1011 | |||
| 1012 | /* | ||
| 1013 | Open a table (skipping table cache) and add it into | ||
| 1014 | THD::temporary_tables list. | ||
| 1015 | */ | ||
| 1016 |
1/2✓ Branch 0 taken 51196 times.
✗ Branch 1 not taken.
|
51196 | TABLE *table = open_table_uncached(thd, path, db, table_name, true, true, |
| 1017 | 51196 | *tmp_table_ptr.get()); | |
| 1018 | |||
| 1019 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 51196 times.
|
51196 | if (!table) { |
| 1020 | ✗ | (void)rm_temporary_table(thd, create_info->db_type, path, | |
| 1021 | ✗ | tmp_table_ptr.get()); | |
| 1022 | ✗ | return true; | |
| 1023 | } | ||
| 1024 | |||
| 1025 | // Transfer ownership of dd::Table object to TABLE_SHARE. | ||
| 1026 | 51196 | table->s->tmp_table_def = tmp_table_ptr.release(); | |
| 1027 | |||
| 1028 | 51196 | thd->thread_specific_used = true; | |
| 1029 | |||
| 1030 |
2/2✓ Branch 0 taken 50323 times.
✓ Branch 1 taken 873 times.
|
51196 | if (binlog_to_trx_cache != nullptr) |
| 1031 | 50323 | *binlog_to_trx_cache = table->file->has_transactions(); | |
| 1032 | 51196 | return false; | |
| 1033 | 52458 | } | |
| 1034 | |||
| 1035 | /** | ||
| 1036 | Create table definition in the Data Dictionary. The table is also | ||
| 1037 | created in the storage engine, depending on the 'no_ha_table' argument. | ||
| 1038 | |||
| 1039 | @param thd Thread handler | ||
| 1040 | @param path Name of file (including database) | ||
| 1041 | @param sch_obj Schema. | ||
| 1042 | @param db Schema name. | ||
| 1043 | Cannot use dd::Schema::name() directly due to | ||
| 1044 | LCTN. | ||
| 1045 | @param table_name Table name | ||
| 1046 | @param create_info create info parameters | ||
| 1047 | @param create_fields Fields to create | ||
| 1048 | @param keys number of keys to create | ||
| 1049 | @param key_info Keys to create | ||
| 1050 | @param keys_onoff Enable or disable keys. | ||
| 1051 | @param fk_keys Number of foreign keys to create | ||
| 1052 | @param fk_key_info Foreign keys to create | ||
| 1053 | @param check_cons_spec List of check constraint specifications. | ||
| 1054 | @param file Handler to use | ||
| 1055 | @param no_ha_table Indicates that only definitions needs to be | ||
| 1056 | created and not a table in the storage engine. | ||
| 1057 | @param do_not_store_in_dd Indicates that we should postpone storing table | ||
| 1058 | object in the data-dictionary. Requires SE | ||
| 1059 | supporting atomic DDL and no_ha_table flag set. | ||
| 1060 | @param part_info Reference to partitioning data structure. | ||
| 1061 | @param[out] binlog_to_trx_cache | ||
| 1062 | Which binlog cache should be used? | ||
| 1063 | If true => trx cache | ||
| 1064 | If false => stmt cache | ||
| 1065 | @param[out] table_def_ptr dd::Table object describing the table | ||
| 1066 | created if do_not_store_in_dd option was | ||
| 1067 | used. Not set otherwise. | ||
| 1068 | @param[out] post_ddl_ht Set to handlerton for table's SE, if this SE | ||
| 1069 | supports atomic DDL, so caller can call SE | ||
| 1070 | post DDL hook after committing transaction. | ||
| 1071 | |||
| 1072 | @note For engines supporting atomic DDL the caller must rollback | ||
| 1073 | both statement and transaction on failure. This must be done | ||
| 1074 | before any further accesses to DD. @sa dd::create_table(). | ||
| 1075 | |||
| 1076 | @retval false ok | ||
| 1077 | @retval true error | ||
| 1078 | */ | ||
| 1079 | |||
| 1080 | 690936 | static bool rea_create_base_table( | |
| 1081 | THD *thd, const char *path, const dd::Schema &sch_obj, const char *db, | ||
| 1082 | const char *table_name, HA_CREATE_INFO *create_info, | ||
| 1083 | List<Create_field> &create_fields, uint keys, KEY *key_info, | ||
| 1084 | Alter_info::enum_enable_or_disable keys_onoff, uint fk_keys, | ||
| 1085 | FOREIGN_KEY *fk_key_info, | ||
| 1086 | const Sql_check_constraint_spec_list *check_cons_spec, handler *file, | ||
| 1087 | bool no_ha_table, bool do_not_store_in_dd, partition_info *part_info, | ||
| 1088 | bool *binlog_to_trx_cache, std::unique_ptr<dd::Table> *table_def_ptr, | ||
| 1089 | handlerton **post_ddl_ht) { | ||
| 1090 |
1/2✓ Branch 0 taken 690948 times.
✗ Branch 1 not taken.
|
690936 | DBUG_TRACE; |
| 1091 | |||
| 1092 | std::unique_ptr<dd::Table> table_def_res = dd::create_table( | ||
| 1093 | thd, sch_obj, table_name, create_info, create_fields, key_info, keys, | ||
| 1094 |
2/4✓ Branch 0 taken 690948 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 690938 times.
✗ Branch 3 not taken.
|
690948 | keys_onoff, fk_key_info, fk_keys, check_cons_spec, file); |
| 1095 | |||
| 1096 |
2/2✓ Branch 0 taken 102 times.
✓ Branch 1 taken 690845 times.
|
690949 | if (!table_def_res) return true; |
| 1097 | |||
| 1098 |
1/2✓ Branch 0 taken 690835 times.
✗ Branch 1 not taken.
|
690845 | dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client()); |
| 1099 | 690835 | dd::Table *table_def = nullptr; | |
| 1100 | |||
| 1101 |
2/2✓ Branch 0 taken 61933 times.
✓ Branch 1 taken 628902 times.
|
690835 | if (do_not_store_in_dd) { |
| 1102 | /* | ||
| 1103 | Clean up code assumes that SE supports atomic DDL if do_not_store_in_dd | ||
| 1104 | was requested, so we can simply rollback our changes. | ||
| 1105 | |||
| 1106 | ha_create_table() won't work correctly if dd::Table object is not stored | ||
| 1107 | in the data-dictionary. | ||
| 1108 | |||
| 1109 | For data-dictionary tables we rely on Dictionary_client::store() to update | ||
| 1110 | their table definition. | ||
| 1111 | */ | ||
| 1112 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 61933 times.
|
61933 | assert(create_info->db_type->flags & HTON_SUPPORTS_ATOMIC_DDL); |
| 1113 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 61933 times.
|
61933 | assert(no_ha_table); |
| 1114 |
5/10✓ Branch 0 taken 61933 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 61933 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 61933 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 61933 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 61933 times.
|
61933 | assert(!dd::get_dictionary()->get_dd_table(db, table_name)); |
| 1115 | |||
| 1116 | 61933 | *table_def_ptr = std::move(table_def_res); | |
| 1117 | |||
| 1118 | 61933 | table_def = table_def_ptr->get(); | |
| 1119 | } else { | ||
| 1120 |
1/2✓ Branch 0 taken 628914 times.
✗ Branch 1 not taken.
|
628902 | bool result = thd->dd_client()->store(table_def_res.get()); |
| 1121 | |||
| 1122 |
4/4✓ Branch 0 taken 114199 times.
✓ Branch 1 taken 514715 times.
✓ Branch 2 taken 96892 times.
✓ Branch 3 taken 532022 times.
|
743113 | if (!(create_info->db_type->flags & HTON_SUPPORTS_ATOMIC_DDL) && |
| 1123 |
2/2✓ Branch 0 taken 96892 times.
✓ Branch 1 taken 17307 times.
|
114199 | !thd->is_plugin_fake_ddl()) |
| 1124 |
1/2✓ Branch 0 taken 96892 times.
✗ Branch 1 not taken.
|
96892 | result = trans_intermediate_ddl_commit(thd, result); |
| 1125 | |||
| 1126 |
2/2✓ Branch 0 taken 35 times.
✓ Branch 1 taken 628879 times.
|
628914 | if (result) return true; |
| 1127 | |||
| 1128 |
4/8✓ Branch 0 taken 628880 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 628880 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 628879 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 628879 times.
|
628879 | if (thd->dd_client()->acquire_for_modification(db, table_name, &table_def)) |
| 1129 | ✗ | return true; | |
| 1130 | } | ||
| 1131 | |||
| 1132 |
2/2✓ Branch 0 taken 488760 times.
✓ Branch 1 taken 202052 times.
|
690812 | if (no_ha_table) { |
| 1133 |
2/2✓ Branch 0 taken 2728 times.
✓ Branch 1 taken 486032 times.
|
488760 | if (part_info) { |
| 1134 | /* | ||
| 1135 | For partitioned tables we can't find some problems with table | ||
| 1136 | until table is opened. Therefore in order to disallow creation | ||
| 1137 | of corrupted tables we have to try to open table as the part | ||
| 1138 | of its creation process. | ||
| 1139 | In cases when both .FRM and SE part of table are created table | ||
| 1140 | is implicitly open in ha_create_table() call. | ||
| 1141 | In cases when we create .FRM without SE part we have to open | ||
| 1142 | table explicitly. | ||
| 1143 | */ | ||
| 1144 |
1/2✓ Branch 0 taken 2728 times.
✗ Branch 1 not taken.
|
2728 | TABLE table; |
| 1145 |
1/2✓ Branch 0 taken 2728 times.
✗ Branch 1 not taken.
|
2728 | TABLE_SHARE share; |
| 1146 | |||
| 1147 |
1/2✓ Branch 0 taken 2728 times.
✗ Branch 1 not taken.
|
2728 | init_tmp_table_share(thd, &share, db, 0, table_name, path, nullptr); |
| 1148 | |||
| 1149 |
2/4✓ Branch 0 taken 2728 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2728 times.
✗ Branch 3 not taken.
|
5456 | bool result = open_table_def(thd, &share, *table_def) || |
| 1150 |
3/4✓ Branch 0 taken 2728 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 36 times.
✓ Branch 3 taken 2692 times.
|
2728 | open_table_from_share(thd, &share, "", 0, (uint)READ_ALL, 0, |
| 1151 | 2728 | &table, true, nullptr); | |
| 1152 | |||
| 1153 | /* | ||
| 1154 | Assert that the change list is empty as no partition function currently | ||
| 1155 | needs to modify item tree. May need call THD::rollback_item_tree_changes | ||
| 1156 | later before calling closefrm if the change list is not empty. | ||
| 1157 | */ | ||
| 1158 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2728 times.
|
2728 | assert(thd->change_list.is_empty()); |
| 1159 |
3/4✓ Branch 0 taken 2692 times.
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 2692 times.
✗ Branch 3 not taken.
|
2728 | if (!result) (void)closefrm(&table, false); |
| 1160 | |||
| 1161 |
1/2✓ Branch 0 taken 2728 times.
✗ Branch 1 not taken.
|
2728 | free_table_share(&share); |
| 1162 | |||
| 1163 |
2/2✓ Branch 0 taken 36 times.
✓ Branch 1 taken 2692 times.
|
2728 | if (result) { |
| 1164 | /* | ||
| 1165 | If changes were committed remove table from DD. | ||
| 1166 | We ignore the errors returned from there functions | ||
| 1167 | as we anyway report error. | ||
| 1168 | */ | ||
| 1169 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
|
36 | if (!(create_info->db_type->flags & HTON_SUPPORTS_ATOMIC_DDL)) { |
| 1170 | ✗ | bool drop_result = dd::drop_table(thd, db, table_name, *table_def); | |
| 1171 | ✗ | (void)trans_intermediate_ddl_commit(thd, drop_result); | |
| 1172 | } | ||
| 1173 | |||
| 1174 | 36 | return true; | |
| 1175 | } | ||
| 1176 |
4/4✓ Branch 0 taken 2692 times.
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 2692 times.
✓ Branch 3 taken 36 times.
|
2764 | } |
| 1177 | |||
| 1178 | 488724 | return false; | |
| 1179 | } | ||
| 1180 | |||
| 1181 |
2/2✓ Branch 0 taken 121256 times.
✓ Branch 1 taken 80796 times.
|
202052 | if ((create_info->db_type->flags & HTON_SUPPORTS_ATOMIC_DDL) && |
| 1182 |
1/2✓ Branch 0 taken 121256 times.
✗ Branch 1 not taken.
|
121256 | create_info->db_type->post_ddl) |
| 1183 | 121256 | *post_ddl_ht = create_info->db_type; | |
| 1184 | |||
| 1185 |
3/4✓ Branch 0 taken 202030 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1018 times.
✓ Branch 3 taken 201012 times.
|
202052 | if (ha_create_table(thd, path, db, table_name, create_info, &create_fields, |
| 1186 | false, false, table_def)) { | ||
| 1187 | /* | ||
| 1188 | Remove table from data-dictionary if it was added and rollback | ||
| 1189 | won't do this automatically. | ||
| 1190 | */ | ||
| 1191 |
2/2✓ Branch 0 taken 279 times.
✓ Branch 1 taken 739 times.
|
1018 | if (!(create_info->db_type->flags & HTON_SUPPORTS_ATOMIC_DDL)) { |
| 1192 | /* | ||
| 1193 | We ignore error from dd_drop_table() as we anyway | ||
| 1194 | return 'true' failure below. | ||
| 1195 | */ | ||
| 1196 |
1/2✓ Branch 0 taken 279 times.
✗ Branch 1 not taken.
|
279 | bool result = dd::drop_table(thd, db, table_name, *table_def); |
| 1197 |
1/2✓ Branch 0 taken 279 times.
✗ Branch 1 not taken.
|
279 | if (!thd->is_plugin_fake_ddl()) |
| 1198 |
1/2✓ Branch 0 taken 279 times.
✗ Branch 1 not taken.
|
279 | (void)trans_intermediate_ddl_commit(thd, result); |
| 1199 | } | ||
| 1200 | 1018 | return true; | |
| 1201 | } else { | ||
| 1202 |
2/4✓ Branch 0 taken 201012 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 201012 times.
|
201012 | if (compression_dict::cols_table_insert(thd, *table_def)) { |
| 1203 | ✗ | return true; | |
| 1204 | } | ||
| 1205 | } | ||
| 1206 | |||
| 1207 | /* | ||
| 1208 | If the SE supports atomic DDL, we can use the trx binlog cache. | ||
| 1209 | Otherwise we must use the statement cache. | ||
| 1210 | */ | ||
| 1211 |
2/2✓ Branch 0 taken 192739 times.
✓ Branch 1 taken 8273 times.
|
201012 | if (binlog_to_trx_cache != nullptr) |
| 1212 | 192739 | *binlog_to_trx_cache = | |
| 1213 | 192739 | (create_info->db_type->flags & HTON_SUPPORTS_ATOMIC_DDL); | |
| 1214 | |||
| 1215 | 201012 | return false; | |
| 1216 | 690927 | } | |
| 1217 | |||
| 1218 | /* | ||
| 1219 | SYNOPSIS | ||
| 1220 | write_bin_log() | ||
| 1221 | thd Thread object | ||
| 1222 | clear_error is clear_error to be called | ||
| 1223 | query Query to log | ||
| 1224 | query_length Length of query | ||
| 1225 | is_trans if the event changes either | ||
| 1226 | a trans or non-trans engine. | ||
| 1227 | |||
| 1228 | RETURN VALUES | ||
| 1229 | NONE | ||
| 1230 | |||
| 1231 | DESCRIPTION | ||
| 1232 | Write the binlog if open, routine used in multiple places in this | ||
| 1233 | file | ||
| 1234 | */ | ||
| 1235 | |||
| 1236 | 898064 | int write_bin_log(THD *thd, bool clear_error, const char *query, | |
| 1237 | size_t query_length, bool is_trans) { | ||
| 1238 | 898064 | int error = 0; | |
| 1239 |
2/2✓ Branch 0 taken 337677 times.
✓ Branch 1 taken 560387 times.
|
898064 | if (mysql_bin_log.is_open()) { |
| 1240 | 337677 | int errcode = 0; | |
| 1241 |
2/2✓ Branch 0 taken 289985 times.
✓ Branch 1 taken 47692 times.
|
337677 | if (clear_error) |
| 1242 | 289985 | thd->clear_error(); | |
| 1243 | else | ||
| 1244 | 47692 | errcode = query_error_code(thd, true); | |
| 1245 | 337677 | error = thd->binlog_query(THD::STMT_QUERY_TYPE, query, query_length, | |
| 1246 | is_trans, false, false, errcode); | ||
| 1247 | } | ||
| 1248 | 898064 | return error; | |
| 1249 | } | ||
| 1250 | |||
| 1251 | 252790 | bool lock_trigger_names(THD *thd, TABLE_LIST *tables) { | |
| 1252 |
2/2✓ Branch 0 taken 316606 times.
✓ Branch 1 taken 252790 times.
|
569396 | for (TABLE_LIST *table = tables; table; table = table->next_global) { |
| 1253 |
3/4✓ Branch 0 taken 316606 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 44229 times.
✓ Branch 3 taken 272377 times.
|
633212 | if (table->open_type == OT_TEMPORARY_ONLY || |
| 1254 |
4/4✓ Branch 0 taken 305504 times.
✓ Branch 1 taken 11102 times.
✓ Branch 2 taken 44229 times.
✓ Branch 3 taken 261275 times.
|
316606 | (table->open_type == OT_TEMPORARY_OR_BASE && is_temporary_table(table))) |
| 1255 | 57953 | continue; | |
| 1256 | |||
| 1257 |
1/2✓ Branch 0 taken 272377 times.
✗ Branch 1 not taken.
|
272377 | dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client()); |
| 1258 | |||
| 1259 | 272377 | const dd::Table *table_obj = nullptr; | |
| 1260 |
4/8✓ Branch 0 taken 272377 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 272377 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 272377 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 272377 times.
|
272377 | if (thd->dd_client()->acquire(table->db, table->table_name, &table_obj)) { |
| 1261 | // Error is reported by the dictionary subsystem. | ||
| 1262 | ✗ | return true; | |
| 1263 | } | ||
| 1264 |
2/2✓ Branch 0 taken 13724 times.
✓ Branch 1 taken 258653 times.
|
272377 | if (table_obj == nullptr) continue; |
| 1265 | |||
| 1266 |
6/10✓ Branch 0 taken 258653 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 258653 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 258653 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1839 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1839 times.
✓ Branch 9 taken 258653 times.
|
260492 | for (const dd::Trigger *trigger : table_obj->triggers()) { |
| 1267 |
2/4✓ Branch 0 taken 1839 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1839 times.
|
1839 | if (acquire_exclusive_mdl_for_trigger(thd, table->db, |
| 1268 |
1/2✓ Branch 0 taken 1839 times.
✗ Branch 1 not taken.
|
1839 | trigger->name().c_str())) |
| 1269 | ✗ | return true; | |
| 1270 | } | ||
| 1271 |
2/3✓ Branch 0 taken 258653 times.
✓ Branch 1 taken 13724 times.
✗ Branch 2 not taken.
|
272377 | } |
| 1272 | |||
| 1273 | 252790 | return false; | |
| 1274 | } | ||
| 1275 | |||
| 1276 | /** | ||
| 1277 | Add MDL requests for specified lock type on all tables referenced by the | ||
| 1278 | given dd::Table object to the list. Also add the referenced table names to | ||
| 1279 | the foreign key invalidator, to be used at a later stage to invalidate the | ||
| 1280 | dd::Table objects. | ||
| 1281 | |||
| 1282 | @param thd Thread handle. | ||
| 1283 | @param table_def dd::Table object. | ||
| 1284 | @param lock_type Type of MDL requests to add. | ||
| 1285 | @param hton Handlerton for table's storage engine. | ||
| 1286 | @param[in,out] mdl_requests List to which MDL requests are to be added. | ||
| 1287 | @param[in,out] fk_invalidator Object keeping track of which dd::Table | ||
| 1288 | objects to invalidate. | ||
| 1289 | |||
| 1290 | @retval operation outcome, false if no error. | ||
| 1291 | */ | ||
| 1292 | 224376 | static bool collect_fk_parents_for_all_fks( | |
| 1293 | THD *thd, const dd::Table *table_def, handlerton *hton, | ||
| 1294 | enum_mdl_type lock_type, MDL_request_list *mdl_requests, | ||
| 1295 | Foreign_key_parents_invalidator *fk_invalidator) { | ||
| 1296 |
6/10✓ Branch 0 taken 224376 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 224376 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 224376 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1437 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1437 times.
✓ Branch 9 taken 224376 times.
|
225813 | for (const dd::Foreign_key *fk : table_def->foreign_keys()) { |
| 1297 | char buff_db[NAME_LEN + 1]; | ||
| 1298 | char buff_table[NAME_LEN + 1]; | ||
| 1299 | |||
| 1300 |
1/2✓ Branch 0 taken 1437 times.
✗ Branch 1 not taken.
|
1437 | my_stpncpy(buff_db, fk->referenced_table_schema_name().c_str(), NAME_LEN); |
| 1301 |
1/2✓ Branch 0 taken 1437 times.
✗ Branch 1 not taken.
|
1437 | my_stpncpy(buff_table, fk->referenced_table_name().c_str(), NAME_LEN); |
| 1302 | |||
| 1303 | /* | ||
| 1304 | In lower-case-table-names == 2 mode we store original versions of table | ||
| 1305 | and db names in the data-dictionary. Hence they need to be lowercased | ||
| 1306 | to produce correct MDL key for them and for other uses. | ||
| 1307 | */ | ||
| 1308 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1437 times.
|
1437 | if (lower_case_table_names == 2) { |
| 1309 | ✗ | my_casedn_str(system_charset_info, buff_db); | |
| 1310 | ✗ | my_casedn_str(system_charset_info, buff_table); | |
| 1311 | } | ||
| 1312 | |||
| 1313 |
1/2✓ Branch 0 taken 1437 times.
✗ Branch 1 not taken.
|
1437 | MDL_request *mdl_request = new (thd->mem_root) MDL_request; |
| 1314 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1437 times.
|
1437 | if (mdl_request == nullptr) return true; |
| 1315 | |||
| 1316 |
1/2✓ Branch 0 taken 1437 times.
✗ Branch 1 not taken.
|
1437 | MDL_REQUEST_INIT(mdl_request, MDL_key::TABLE, buff_db, buff_table, |
| 1317 | lock_type, MDL_STATEMENT); | ||
| 1318 | |||
| 1319 |
1/2✓ Branch 0 taken 1437 times.
✗ Branch 1 not taken.
|
1437 | mdl_requests->push_front(mdl_request); |
| 1320 | |||
| 1321 |
1/2✓ Branch 0 taken 1437 times.
✗ Branch 1 not taken.
|
1437 | mdl_request = new (thd->mem_root) MDL_request; |
| 1322 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1437 times.
|
1437 | if (mdl_request == nullptr) return true; |
| 1323 | |||
| 1324 |
1/2✓ Branch 0 taken 1437 times.
✗ Branch 1 not taken.
|
1437 | MDL_REQUEST_INIT(mdl_request, MDL_key::SCHEMA, buff_db, "", |
| 1325 | MDL_INTENTION_EXCLUSIVE, MDL_STATEMENT); | ||
| 1326 | |||
| 1327 |
1/2✓ Branch 0 taken 1437 times.
✗ Branch 1 not taken.
|
1437 | mdl_requests->push_front(mdl_request); |
| 1328 | |||
| 1329 |
3/4✓ Branch 0 taken 28 times.
✓ Branch 1 taken 1409 times.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
|
1437 | if (fk_invalidator) fk_invalidator->add(buff_db, buff_table, hton); |
| 1330 | } | ||
| 1331 | 224376 | return false; | |
| 1332 | } | ||
| 1333 | |||
| 1334 | /** | ||
| 1335 | Add MDL requests for specified lock type on all tables referencing | ||
| 1336 | the given table. | ||
| 1337 | |||
| 1338 | @param thd Thread handle. | ||
| 1339 | @param table_def dd::Table object describing the table. | ||
| 1340 | @param lock_type Type of MDL requests to add. | ||
| 1341 | @param[in,out] mdl_requests List to which MDL requests are to be added. | ||
| 1342 | |||
| 1343 | @retval operation outcome, false if no error. | ||
| 1344 | */ | ||
| 1345 | 296055 | static bool collect_fk_children(THD *thd, const dd::Table *table_def, | |
| 1346 | enum_mdl_type lock_type, | ||
| 1347 | MDL_request_list *mdl_requests) { | ||
| 1348 |
3/4✓ Branch 0 taken 296055 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 602 times.
✓ Branch 3 taken 296055 times.
|
296657 | for (const dd::Foreign_key_parent *fk : table_def->foreign_key_parents()) { |
| 1349 | char buff_db[NAME_LEN + 1]; | ||
| 1350 | char buff_table[NAME_LEN + 1]; | ||
| 1351 | 602 | my_stpncpy(buff_db, fk->child_schema_name().c_str(), NAME_LEN); | |
| 1352 | 602 | my_stpncpy(buff_table, fk->child_table_name().c_str(), NAME_LEN); | |
| 1353 | |||
| 1354 | /* | ||
| 1355 | In lower-case-table-names == 2 mode we store original versions of table | ||
| 1356 | and db names in the data-dictionary. Hence they need to be lowercased | ||
| 1357 | to produce correct MDL key for them and for other uses. | ||
| 1358 | */ | ||
| 1359 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 602 times.
|
602 | if (lower_case_table_names == 2) { |
| 1360 | ✗ | my_casedn_str(system_charset_info, buff_db); | |
| 1361 | ✗ | my_casedn_str(system_charset_info, buff_table); | |
| 1362 | } | ||
| 1363 | |||
| 1364 |
1/2✓ Branch 0 taken 602 times.
✗ Branch 1 not taken.
|
602 | MDL_request *mdl_request = new (thd->mem_root) MDL_request; |
| 1365 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 602 times.
|
602 | if (mdl_request == nullptr) return true; |
| 1366 | |||
| 1367 |
1/2✓ Branch 0 taken 602 times.
✗ Branch 1 not taken.
|
602 | MDL_REQUEST_INIT(mdl_request, MDL_key::TABLE, buff_db, buff_table, |
| 1368 | lock_type, MDL_STATEMENT); | ||
| 1369 | |||
| 1370 |
1/2✓ Branch 0 taken 602 times.
✗ Branch 1 not taken.
|
602 | mdl_requests->push_front(mdl_request); |
| 1371 | |||
| 1372 |
1/2✓ Branch 0 taken 602 times.
✗ Branch 1 not taken.
|
602 | mdl_request = new (thd->mem_root) MDL_request; |
| 1373 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 602 times.
|
602 | if (mdl_request == nullptr) return true; |
| 1374 | |||
| 1375 |
1/2✓ Branch 0 taken 602 times.
✗ Branch 1 not taken.
|
602 | MDL_REQUEST_INIT(mdl_request, MDL_key::SCHEMA, buff_db, "", |
| 1376 | MDL_INTENTION_EXCLUSIVE, MDL_STATEMENT); | ||
| 1377 | |||
| 1378 |
1/2✓ Branch 0 taken 602 times.
✗ Branch 1 not taken.
|
602 | mdl_requests->push_front(mdl_request); |
| 1379 | } | ||
| 1380 | |||
| 1381 | 296055 | return false; | |
| 1382 | } | ||
| 1383 | |||
| 1384 | /** | ||
| 1385 | Add MDL requests for exclusive lock on all foreign key names on the given | ||
| 1386 | table to the list. | ||
| 1387 | |||
| 1388 | @param thd Thread context. | ||
| 1389 | @param db Table's schema name. | ||
| 1390 | @param table_def Table definition. | ||
| 1391 | @param[in,out] mdl_requests List to which MDL requests are to be added. | ||
| 1392 | |||
| 1393 | @retval operation outcome, false if no error. | ||
| 1394 | */ | ||
| 1395 | |||
| 1396 | 133811 | static bool collect_fk_names(THD *thd, const char *db, | |
| 1397 | const dd::Table *table_def, | ||
| 1398 | MDL_request_list *mdl_requests) { | ||
| 1399 |
6/10✓ Branch 0 taken 133811 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 133811 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 133811 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1031 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1031 times.
✓ Branch 9 taken 133811 times.
|
134842 | for (const dd::Foreign_key *fk : table_def->foreign_keys()) { |
| 1400 | /* | ||
| 1401 | Since foreign key names are case-insensitive we need to lowercase them | ||
| 1402 | before passing to MDL subsystem. | ||
| 1403 | */ | ||
| 1404 | char fk_name[NAME_LEN + 1]; | ||
| 1405 |
2/4✓ Branch 0 taken 1031 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1031 times.
✗ Branch 3 not taken.
|
1031 | strmake(fk_name, fk->name().c_str(), NAME_LEN); |
| 1406 |
1/2✓ Branch 0 taken 1031 times.
✗ Branch 1 not taken.
|
1031 | my_casedn_str(system_charset_info, fk_name); |
| 1407 | |||
| 1408 |
1/2✓ Branch 0 taken 1031 times.
✗ Branch 1 not taken.
|
1031 | MDL_request *mdl_request = new (thd->mem_root) MDL_request; |
| 1409 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1031 times.
|
1031 | if (mdl_request == nullptr) return true; |
| 1410 | |||
| 1411 |
1/2✓ Branch 0 taken 1031 times.
✗ Branch 1 not taken.
|
1031 | MDL_REQUEST_INIT(mdl_request, MDL_key::FOREIGN_KEY, db, fk_name, |
| 1412 | MDL_EXCLUSIVE, MDL_STATEMENT); | ||
| 1413 | |||
| 1414 |
1/2✓ Branch 0 taken 1031 times.
✗ Branch 1 not taken.
|
1031 | mdl_requests->push_front(mdl_request); |
| 1415 | } | ||
| 1416 | |||
| 1417 | 133811 | return false; | |
| 1418 | } | ||
| 1419 | |||
| 1420 | 151509 | bool rm_table_do_discovery_and_lock_fk_tables(THD *thd, TABLE_LIST *tables) { | |
| 1421 | 151509 | MEM_ROOT mdl_reqs_root(key_memory_rm_db_mdl_reqs_root, MEM_ROOT_BLOCK_SIZE); | |
| 1422 |
1/2✓ Branch 0 taken 151509 times.
✗ Branch 1 not taken.
|
151509 | MDL_request_list mdl_requests; |
| 1423 | |||
| 1424 |
2/2✓ Branch 0 taken 188936 times.
✓ Branch 1 taken 151509 times.
|
340445 | for (TABLE_LIST *table = tables; table; table = table->next_local) { |
| 1425 |
6/6✓ Branch 0 taken 177834 times.
✓ Branch 1 taken 11102 times.
✓ Branch 2 taken 43041 times.
✓ Branch 3 taken 134793 times.
✓ Branch 4 taken 43041 times.
✓ Branch 5 taken 145895 times.
|
201062 | if (table->open_type != OT_BASE_ONLY && is_temporary_table(table)) continue; |
| 1426 | |||
| 1427 |
1/2✓ Branch 0 taken 145895 times.
✗ Branch 1 not taken.
|
145895 | dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client()); |
| 1428 | |||
| 1429 | 145895 | const dd::Abstract_table *abstract_table_def = nullptr; | |
| 1430 |
4/8✓ Branch 0 taken 145895 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 145895 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 145895 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 145895 times.
|
145895 | if (thd->dd_client()->acquire(table->db, table->table_name, |
| 1431 | &abstract_table_def)) | ||
| 1432 | ✗ | return true; | |
| 1433 | |||
| 1434 |
2/2✓ Branch 0 taken 11259 times.
✓ Branch 1 taken 134636 times.
|
145895 | if (!abstract_table_def) { |
| 1435 | /* | ||
| 1436 | If table is missing try to discover it from some storage engine | ||
| 1437 | as it might have foreign keys. | ||
| 1438 | */ | ||
| 1439 |
1/2✓ Branch 0 taken 11259 times.
✗ Branch 1 not taken.
|
11259 | int result = ha_create_table_from_engine( |
| 1440 | thd, table->db, | ||
| 1441 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11259 times.
|
11259 | (lower_case_table_names == 2) ? table->alias : table->table_name); |
| 1442 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11259 times.
|
11259 | if (result > 0) { |
| 1443 | // Error during discovery, error should be reported already. | ||
| 1444 | ✗ | return true; | |
| 1445 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11259 times.
|
11259 | } else if (result == 0) { |
| 1446 | // Table was discovered. Re-try to retrieve its definition. | ||
| 1447 | ✗ | if (thd->dd_client()->acquire(table->db, table->table_name, | |
| 1448 | &abstract_table_def)) | ||
| 1449 | ✗ | return true; | |
| 1450 | } else // result < 0 | ||
| 1451 | { | ||
| 1452 | // No table was found. | ||
| 1453 | } | ||
| 1454 | } | ||
| 1455 | |||
| 1456 |
4/4✓ Branch 0 taken 134636 times.
✓ Branch 1 taken 11259 times.
✓ Branch 2 taken 12126 times.
✓ Branch 3 taken 133769 times.
|
280531 | if (!abstract_table_def || |
| 1457 |
3/4✓ Branch 0 taken 134636 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 867 times.
✓ Branch 3 taken 133769 times.
|
134636 | abstract_table_def->type() != dd::enum_table_type::BASE_TABLE) |
| 1458 | 12126 | continue; | |
| 1459 | |||
| 1460 | const dd::Table *table_def = | ||
| 1461 |
1/2✓ Branch 0 taken 133769 times.
✗ Branch 1 not taken.
|
133769 | dynamic_cast<const dd::Table *>(abstract_table_def); |
| 1462 | |||
| 1463 | /* | ||
| 1464 | Ensure that we don't hold memory used by MDL_requests after locks | ||
| 1465 | have been acquired. This reduces memory usage in cases when we have | ||
| 1466 | DROP DATABASE that needs to drop lots of different objects. | ||
| 1467 | */ | ||
| 1468 | 133769 | MEM_ROOT *save_thd_mem_root = thd->mem_root; | |
| 1469 | auto restore_thd_mem_root = | ||
| 1470 |
1/2✓ Branch 0 taken 133769 times.
✗ Branch 1 not taken.
|
133769 | create_scope_guard([&]() { thd->mem_root = save_thd_mem_root; }); |
| 1471 | 133769 | thd->mem_root = &mdl_reqs_root; | |
| 1472 | |||
| 1473 |
2/4✓ Branch 0 taken 133769 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 133769 times.
|
133769 | if (collect_fk_parents_for_all_fks(thd, table_def, nullptr, MDL_EXCLUSIVE, |
| 1474 | &mdl_requests, nullptr)) | ||
| 1475 | ✗ | return true; | |
| 1476 | |||
| 1477 |
2/4✓ Branch 0 taken 133769 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 133769 times.
|
133769 | if (collect_fk_children(thd, table_def, MDL_EXCLUSIVE, &mdl_requests)) |
| 1478 | ✗ | return true; | |
| 1479 | |||
| 1480 |
2/4✓ Branch 0 taken 133769 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 133769 times.
|
133769 | if (collect_fk_names(thd, table->db, table_def, &mdl_requests)) return true; |
| 1481 |
3/5✓ Branch 0 taken 133769 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 133769 times.
✓ Branch 3 taken 12126 times.
✗ Branch 4 not taken.
|
145895 | } |
| 1482 | |||
| 1483 |
3/4✓ Branch 0 taken 719 times.
✓ Branch 1 taken 150790 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 151509 times.
|
152228 | if (!mdl_requests.is_empty() && |
| 1484 |
2/4✓ Branch 0 taken 719 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 719 times.
|
719 | thd->mdl_context.acquire_locks(&mdl_requests, |
| 1485 | thd->variables.lock_wait_timeout)) | ||
| 1486 | ✗ | return true; | |
| 1487 | |||
| 1488 | 151509 | return false; | |
| 1489 | 151509 | } | |
| 1490 | |||
| 1491 | 601850 | void Foreign_key_parents_invalidator::add(const char *db_name, | |
| 1492 | const char *table_name, | ||
| 1493 | handlerton *hton) { | ||
| 1494 |
1/2✓ Branch 0 taken 601850 times.
✗ Branch 1 not taken.
|
601850 | m_parent_map.insert(typename Parent_map::value_type( |
| 1495 | 1203700 | typename Parent_map::key_type(db_name, table_name), hton)); | |
| 1496 | 601850 | } | |
| 1497 | |||
| 1498 | 852138 | void Foreign_key_parents_invalidator::invalidate(THD *thd) { | |
| 1499 |
3/4✓ Branch 0 taken 493422 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 493422 times.
✓ Branch 3 taken 852138 times.
|
1345560 | for (auto parent_it : m_parent_map) { |
| 1500 | // Invalidate Table and Table Definition Caches too. | ||
| 1501 |
1/2✓ Branch 0 taken 493422 times.
✗ Branch 1 not taken.
|
493422 | mysql_ha_flush_table(thd, parent_it.first.first.c_str(), |
| 1502 | parent_it.first.second.c_str()); | ||
| 1503 |
1/2✓ Branch 0 taken 493422 times.
✗ Branch 1 not taken.
|
493422 | close_all_tables_for_name(thd, parent_it.first.first.c_str(), |
| 1504 | parent_it.first.second.c_str(), false); | ||
| 1505 | |||
| 1506 | /* | ||
| 1507 | TODO: Should revisit the way we do invalidation to avoid | ||
| 1508 | suppressing errors, which is necessary since it's done after | ||
| 1509 | commit. For now, we use an error handler. | ||
| 1510 | */ | ||
| 1511 | 493422 | Dummy_error_handler error_handler; | |
| 1512 |
1/2✓ Branch 0 taken 493422 times.
✗ Branch 1 not taken.
|
493422 | thd->push_internal_handler(&error_handler); |
| 1513 | bool ignored [[maybe_unused]]; | ||
| 1514 |
3/6✓ Branch 0 taken 493422 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 493422 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 493422 times.
✗ Branch 5 not taken.
|
493422 | ignored = thd->dd_client()->invalidate(parent_it.first.first.c_str(), |
| 1515 | parent_it.first.second.c_str()); | ||
| 1516 |
2/6✓ Branch 0 taken 493422 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 493422 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
493422 | DBUG_EXECUTE_IF("fail_while_invalidating_fk_parents", |
| 1517 | { my_error(ER_LOCK_DEADLOCK, MYF(0)); }); | ||
| 1518 |
1/2✓ Branch 0 taken 493422 times.
✗ Branch 1 not taken.
|
493422 | thd->pop_internal_handler(); |
| 1519 | |||
| 1520 | // And storage engine internal dictionary cache as well. | ||
| 1521 | #ifdef DISABLED_UNTIL_WL9533 | ||
| 1522 | /* | ||
| 1523 | TODO: Simply removing entries from InnoDB internal cache breaks | ||
| 1524 | its FK checking logic at the moment. This is to be solved | ||
| 1525 | as part of WL#9533. We might have to replace invalidation | ||
| 1526 | with cache update to do this. | ||
| 1527 | */ | ||
| 1528 | if ((parent_it.second)->dict_cache_reset) | ||
| 1529 | ((parent_it.second)) | ||
| 1530 | ->dict_cache_reset(parent_it.first.first.c_str(), | ||
| 1531 | parent_it.first.second.c_str()); | ||
| 1532 | #endif | ||
| 1533 | 493422 | } | |
| 1534 | |||
| 1535 | 852138 | m_parent_map.clear(); | |
| 1536 | 852138 | } | |
| 1537 | |||
| 1538 | /* | ||
| 1539 | delete (drop) tables. | ||
| 1540 | |||
| 1541 | SYNOPSIS | ||
| 1542 | mysql_rm_table() | ||
| 1543 | thd Thread handle | ||
| 1544 | tables List of tables to delete | ||
| 1545 | if_exists If 1, don't give error if one table doesn't exists | ||
| 1546 | |||
| 1547 | NOTES | ||
| 1548 | Will delete all tables that can be deleted and give a compact error | ||
| 1549 | messages for tables that could not be deleted. | ||
| 1550 | If a table is in use, we will wait for all users to free the table | ||
| 1551 | before dropping it | ||
| 1552 | |||
| 1553 | Wait if global_read_lock (FLUSH TABLES WITH READ LOCK) is set, but | ||
| 1554 | not if under LOCK TABLES. | ||
| 1555 | |||
| 1556 | RETURN | ||
| 1557 | false OK. In this case ok packet is sent to user | ||
| 1558 | true Error | ||
| 1559 | |||
| 1560 | */ | ||
| 1561 | |||
| 1562 | 153362 | bool mysql_rm_table(THD *thd, TABLE_LIST *tables, bool if_exists, | |
| 1563 | bool drop_temporary) { | ||
| 1564 | bool error; | ||
| 1565 | 153362 | Drop_table_error_handler err_handler; | |
| 1566 | TABLE_LIST *table; | ||
| 1567 | 153363 | uint have_non_tmp_table = 0; | |
| 1568 | |||
| 1569 |
1/2✓ Branch 0 taken 153363 times.
✗ Branch 1 not taken.
|
153363 | DBUG_TRACE; |
| 1570 | |||
| 1571 | // DROP table is not allowed in the XA_IDLE or XA_PREPARED transaction states. | ||
| 1572 |
3/4✓ Branch 0 taken 153362 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 153359 times.
|
153363 | if (thd->get_transaction()->xid_state()->check_xa_idle_or_prepared(true)) { |
| 1573 | 3 | return true; | |
| 1574 | } | ||
| 1575 | |||
| 1576 | /* | ||
| 1577 | DROP tables need to have their logging format determined if | ||
| 1578 | in MIXED mode and dropping a TEMP table. | ||
| 1579 | */ | ||
| 1580 |
2/4✓ Branch 0 taken 153360 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 153360 times.
|
153359 | if (thd->decide_logging_format(tables)) { |
| 1581 | ✗ | return true; | |
| 1582 | } | ||
| 1583 | |||
| 1584 | /* Disable drop of enabled log tables, must be done before name locking */ | ||
| 1585 |
2/2✓ Branch 0 taken 185619 times.
✓ Branch 1 taken 153357 times.
|
338976 | for (table = tables; table; table = table->next_local) { |
| 1586 |
3/4✓ Branch 0 taken 185618 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 185616 times.
|
185619 | if (query_logger.check_if_log_table(table, true)) { |
| 1587 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | my_error(ER_BAD_LOG_STATEMENT, MYF(0), "DROP"); |
| 1588 | 2 | return true; | |
| 1589 | } | ||
| 1590 | } | ||
| 1591 | |||
| 1592 |
2/2✓ Branch 0 taken 146114 times.
✓ Branch 1 taken 7243 times.
|
153357 | if (!drop_temporary) { |
| 1593 |
2/2✓ Branch 0 taken 146056 times.
✓ Branch 1 taken 58 times.
|
146114 | if (!thd->locked_tables_mode) { |
| 1594 |
1/2✓ Branch 0 taken 146057 times.
✗ Branch 1 not taken.
|
146056 | if (lock_table_names(thd, tables, nullptr, |
| 1595 |
4/4✓ Branch 0 taken 145978 times.
✓ Branch 1 taken 79 times.
✓ Branch 2 taken 79 times.
✓ Branch 3 taken 145978 times.
|
292035 | thd->variables.lock_wait_timeout, 0) || |
| 1596 |
2/4✓ Branch 0 taken 145978 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 145978 times.
|
145978 | lock_trigger_names(thd, tables)) |
| 1597 | 79 | return true; | |
| 1598 | |||
| 1599 |
3/4✓ Branch 0 taken 145496 times.
✓ Branch 1 taken 482 times.
✓ Branch 2 taken 145496 times.
✗ Branch 3 not taken.
|
145978 | DEBUG_SYNC(thd, "mysql_rm_table_after_lock_table_names"); |
| 1600 | |||
| 1601 |
2/2✓ Branch 0 taken 177765 times.
✓ Branch 1 taken 145978 times.
|
323743 | for (table = tables; table; table = table->next_local) { |
| 1602 |
2/2✓ Branch 0 taken 43035 times.
✓ Branch 1 taken 134730 times.
|
177765 | if (is_temporary_table(table)) continue; |
| 1603 | |||
| 1604 | /* Here we are sure that a non-tmp table exists */ | ||
| 1605 | 134730 | have_non_tmp_table = 1; | |
| 1606 | } | ||
| 1607 | } else { | ||
| 1608 | 58 | bool acquire_backup_lock = false; | |
| 1609 | |||
| 1610 |
2/2✓ Branch 0 taken 85 times.
✓ Branch 1 taken 47 times.
|
132 | for (table = tables; table; table = table->next_local) |
| 1611 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 79 times.
|
85 | if (is_temporary_table(table)) { |
| 1612 | /* | ||
| 1613 | A temporary table. | ||
| 1614 | |||
| 1615 | Don't try to find a corresponding MDL lock or assign it | ||
| 1616 | to table->mdl_request.ticket. There can't be metadata | ||
| 1617 | locks for temporary tables: they are local to the session. | ||
| 1618 | |||
| 1619 | Later in this function we release the MDL lock only if | ||
| 1620 | table->mdl_requeset.ticket is not NULL. Thus here we | ||
| 1621 | ensure that we won't release the metadata lock on the base | ||
| 1622 | table locked with LOCK TABLES as a side effect of temporary | ||
| 1623 | table drop. | ||
| 1624 | */ | ||
| 1625 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | assert(table->mdl_request.ticket == nullptr); |
| 1626 | } else { | ||
| 1627 | /* | ||
| 1628 | Not a temporary table. | ||
| 1629 | |||
| 1630 | Since 'tables' list can't contain duplicates (this is ensured | ||
| 1631 | by parser) it is safe to cache pointer to the TABLE instances | ||
| 1632 | in its elements. | ||
| 1633 | */ | ||
| 1634 |
1/2✓ Branch 0 taken 79 times.
✗ Branch 1 not taken.
|
79 | table->table = find_table_for_mdl_upgrade(thd, table->db, |
| 1635 | table->table_name, false); | ||
| 1636 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 70 times.
|
79 | if (!table->table) return true; |
| 1637 | 70 | table->mdl_request.ticket = table->table->mdl_ticket; | |
| 1638 | |||
| 1639 |
3/4✓ Branch 0 taken 70 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 68 times.
|
70 | if (wait_while_table_is_used(thd, table->table, |
| 1640 | HA_EXTRA_FORCE_REOPEN)) | ||
| 1641 | 2 | return true; | |
| 1642 | |||
| 1643 | /* Here we are sure that a non-tmp table exists */ | ||
| 1644 | 68 | have_non_tmp_table = 1; | |
| 1645 | |||
| 1646 |
2/2✓ Branch 0 taken 46 times.
✓ Branch 1 taken 22 times.
|
68 | if (!acquire_backup_lock) acquire_backup_lock = true; |
| 1647 | } | ||
| 1648 | |||
| 1649 |
3/4✓ Branch 0 taken 41 times.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 47 times.
|
88 | if (acquire_backup_lock && |
| 1650 |
2/4✓ Branch 0 taken 41 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 41 times.
|
41 | acquire_shared_backup_lock(thd, thd->variables.lock_wait_timeout)) |
| 1651 | ✗ | return true; | |
| 1652 | } | ||
| 1653 | |||
| 1654 |
2/4✓ Branch 0 taken 146025 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 146025 times.
|
146025 | if (rm_table_do_discovery_and_lock_fk_tables(thd, tables)) return true; |
| 1655 | |||
| 1656 |
2/4✓ Branch 0 taken 146025 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 146025 times.
|
146025 | if (lock_check_constraint_names(thd, tables)) return true; |
| 1657 | } | ||
| 1658 | |||
| 1659 | 153268 | std::vector<MDL_ticket *> safe_to_release_mdl; | |
| 1660 | |||
| 1661 | { | ||
| 1662 | // This Auto_releaser needs to go out of scope before we start releasing | ||
| 1663 | // metadata locks below. Otherwise we end up having acquired objects for | ||
| 1664 | // which we no longer have any locks held. | ||
| 1665 |
1/2✓ Branch 0 taken 153268 times.
✗ Branch 1 not taken.
|
153268 | dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client()); |
| 1666 | |||
| 1667 | 153268 | std::set<handlerton *> post_ddl_htons; | |
| 1668 | 153268 | Foreign_key_parents_invalidator fk_invalidator; | |
| 1669 | bool not_used; | ||
| 1670 | |||
| 1671 | /* mark for close and remove all cached entries */ | ||
| 1672 |
1/2✓ Branch 0 taken 153268 times.
✗ Branch 1 not taken.
|
153268 | thd->push_internal_handler(&err_handler); |
| 1673 |
1/2✓ Branch 0 taken 153244 times.
✗ Branch 1 not taken.
|
153268 | error = mysql_rm_table_no_locks(thd, tables, if_exists, drop_temporary, |
| 1674 | false, ¬_used, &post_ddl_htons, | ||
| 1675 | &fk_invalidator, &safe_to_release_mdl); | ||
| 1676 |
1/2✓ Branch 0 taken 153244 times.
✗ Branch 1 not taken.
|
153244 | thd->pop_internal_handler(); |
| 1677 | 153244 | } | |
| 1678 | |||
| 1679 |
2/2✓ Branch 0 taken 146001 times.
✓ Branch 1 taken 7243 times.
|
153244 | if (!drop_temporary) { |
| 1680 | /* | ||
| 1681 | Under LOCK TABLES we should release meta-data locks on the tables | ||
| 1682 | which were dropped. | ||
| 1683 | |||
| 1684 | Leave LOCK TABLES mode if we managed to drop all tables which were | ||
| 1685 | locked. Additional check for 'non_temp_tables_count' is to avoid | ||
| 1686 | leaving LOCK TABLES mode if we have dropped only temporary tables. | ||
| 1687 | */ | ||
| 1688 |
2/2✓ Branch 0 taken 47 times.
✓ Branch 1 taken 145954 times.
|
146001 | if (thd->locked_tables_mode) { |
| 1689 | /* | ||
| 1690 | First we need to reopen tables which data-dictionary entries were | ||
| 1691 | updated/invalidated (and thus they were closed) due to fact that | ||
| 1692 | they participate in the same FKs as tables which were dropped. | ||
| 1693 | */ | ||
| 1694 |
2/4✓ Branch 0 taken 47 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 47 times.
|
47 | if (thd->locked_tables_list.reopen_tables(thd)) error = true; |
| 1695 | |||
| 1696 |
5/6✓ Branch 0 taken 47 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 14 times.
✓ Branch 4 taken 29 times.
✓ Branch 5 taken 4 times.
|
47 | if (thd->lock && thd->lock->table_count == 0 && have_non_tmp_table > 0) { |
| 1697 |
1/2✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
|
29 | thd->mdl_context.release_statement_locks(); |
| 1698 |
1/2✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
|
29 | thd->locked_tables_list.unlock_locked_tables(thd); |
| 1699 | } else { | ||
| 1700 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 18 times.
|
30 | for (MDL_ticket *mdl_ticket : safe_to_release_mdl) { |
| 1701 | /* | ||
| 1702 | Under LOCK TABLES we may have several instances of table open | ||
| 1703 | and locked and therefore have to remove several metadata lock | ||
| 1704 | requests associated with them. | ||
| 1705 | */ | ||
| 1706 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | thd->mdl_context.release_all_locks_for_name(mdl_ticket); |
| 1707 | } | ||
| 1708 | } | ||
| 1709 | } | ||
| 1710 | } | ||
| 1711 | |||
| 1712 |
2/2✓ Branch 0 taken 1103 times.
✓ Branch 1 taken 152141 times.
|
153244 | if (error) return true; |
| 1713 | |||
| 1714 |
6/6✓ Branch 0 taken 7152 times.
✓ Branch 1 taken 144989 times.
✓ Branch 2 taken 1352 times.
✓ Branch 3 taken 5800 times.
✓ Branch 4 taken 1352 times.
✓ Branch 5 taken 150789 times.
|
152141 | if (thd->lex->drop_temporary && thd->in_multi_stmt_transaction_mode()) { |
| 1715 | /* | ||
| 1716 | When autocommit is disabled, dropping temporary table sets this flag | ||
| 1717 | to start transaction in any case (regardless of binlog=on/off, | ||
| 1718 | binlog format and transactional/non-transactional engine) to make | ||
| 1719 | behavior consistent. | ||
| 1720 | */ | ||
| 1721 | 1352 | thd->server_status |= SERVER_STATUS_IN_TRANS; | |
| 1722 | } | ||
| 1723 | |||
| 1724 |
2/2✓ Branch 0 taken 12068 times.
✓ Branch 1 taken 140073 times.
|
152141 | if (thd->variables.binlog_format == BINLOG_FORMAT_STMT && |
| 1725 |
4/4✓ Branch 0 taken 2209 times.
✓ Branch 1 taken 9859 times.
✓ Branch 2 taken 163 times.
✓ Branch 3 taken 2046 times.
|
12068 | thd->lex->drop_temporary && (thd->in_sub_stmt & SUB_STMT_FUNCTION) && |
| 1726 |
1/2✓ Branch 0 taken 163 times.
✗ Branch 1 not taken.
|
163 | thd->binlog_evt_union.do_union) { |
| 1727 | /* | ||
| 1728 | This does not write the query into binary log, it just sets | ||
| 1729 | thd->binlog_evt_union.unioned_events to true for writing | ||
| 1730 | its top function call to the binary log on function exit | ||
| 1731 | in mixed mode and statement mode. So this does not cause | ||
| 1732 | any error. | ||
| 1733 | */ | ||
| 1734 |
3/6✓ Branch 0 taken 163 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 163 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 163 times.
✗ Branch 5 not taken.
|
163 | write_bin_log(thd, true, thd->query().str, thd->query().length, true); |
| 1735 | } | ||
| 1736 | |||
| 1737 |
1/2✓ Branch 0 taken 152141 times.
✗ Branch 1 not taken.
|
152141 | my_ok(thd); |
| 1738 | 152141 | return false; | |
| 1739 | 153339 | } | |
| 1740 | |||
| 1741 | /** | ||
| 1742 | Runtime context for DROP TABLES statement. | ||
| 1743 | */ | ||
| 1744 | |||
| 1745 | class Drop_tables_ctx { | ||
| 1746 | public: | ||
| 1747 | 156486 | Drop_tables_ctx(bool if_exists_arg, bool drop_temporary_arg, | |
| 1748 | bool drop_database_arg) | ||
| 1749 | 156486 | : if_exists(if_exists_arg), | |
| 1750 | 156486 | drop_temporary(drop_temporary_arg), | |
| 1751 | 156486 | drop_database(drop_database_arg), | |
| 1752 | 156486 | base_atomic_tables(PSI_INSTRUMENT_ME), | |
| 1753 | 156486 | base_non_atomic_tables(PSI_INSTRUMENT_ME), | |
| 1754 | 156486 | tmp_trans_tables(PSI_INSTRUMENT_ME), | |
| 1755 | 156486 | tmp_trans_tables_to_binlog(PSI_INSTRUMENT_ME), | |
| 1756 | 156486 | tmp_non_trans_tables(PSI_INSTRUMENT_ME), | |
| 1757 | 156486 | tmp_non_trans_tables_to_binlog(PSI_INSTRUMENT_ME), | |
| 1758 | 156486 | nonexistent_tables(PSI_INSTRUMENT_ME), | |
| 1759 | 156486 | views(PSI_INSTRUMENT_ME), | |
| 1760 | 156486 | dropped_non_atomic(PSI_INSTRUMENT_ME), | |
| 1761 | 156486 | gtid_and_table_groups_state(NO_GTID_MANY_TABLE_GROUPS) { | |
| 1762 | /* DROP DATABASE implies if_exists and absence of drop_temporary. */ | ||
| 1763 |
4/6✓ Branch 0 taken 3218 times.
✓ Branch 1 taken 153268 times.
✓ Branch 2 taken 3218 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3218 times.
✗ Branch 5 not taken.
|
156486 | assert(!drop_database || (if_exists && !drop_temporary)); |
| 1764 | 156486 | } | |
| 1765 | |||
| 1766 | /* Parameters of DROP TABLES statement. */ | ||
| 1767 | const bool if_exists; | ||
| 1768 | const bool drop_temporary; | ||
| 1769 | const bool drop_database; | ||
| 1770 | |||
| 1771 | /* Different table groups of tables to be dropped. */ | ||
| 1772 | Prealloced_array<TABLE_LIST *, 1> base_atomic_tables; | ||
| 1773 | Prealloced_array<TABLE_LIST *, 1> base_non_atomic_tables; | ||
| 1774 | Prealloced_array<TABLE_LIST *, 1> tmp_trans_tables; | ||
| 1775 | Prealloced_array<TABLE_LIST *, 1> tmp_trans_tables_to_binlog; | ||
| 1776 | Prealloced_array<TABLE_LIST *, 1> tmp_non_trans_tables; | ||
| 1777 | Prealloced_array<TABLE_LIST *, 1> tmp_non_trans_tables_to_binlog; | ||
| 1778 | Prealloced_array<TABLE_LIST *, 1> nonexistent_tables; | ||
| 1779 | Prealloced_array<TABLE_LIST *, 1> views; | ||
| 1780 | |||
| 1781 | /* Methods which simplify checking state of the above groups. */ | ||
| 1782 | 439486 | bool has_base_atomic_tables() const { return base_atomic_tables.size() != 0; } | |
| 1783 | |||
| 1784 | 283606 | bool has_base_non_atomic_tables() const { | |
| 1785 | 283606 | return base_non_atomic_tables.size() != 0; | |
| 1786 | } | ||
| 1787 | |||
| 1788 | 364596 | bool has_tmp_trans_tables() const { return tmp_trans_tables.size() != 0; } | |
| 1789 | |||
| 1790 | 159791 | bool has_tmp_trans_tables_to_binlog() const { | |
| 1791 | 159791 | return tmp_trans_tables_to_binlog.size() != 0; | |
| 1792 | } | ||
| 1793 | |||
| 1794 | 505489 | bool has_tmp_non_trans_tables() const { | |
| 1795 | 505489 | return tmp_non_trans_tables.size() != 0; | |
| 1796 | } | ||
| 1797 | |||
| 1798 | 158054 | bool has_tmp_non_trans_tables_to_binlog() const { | |
| 1799 | 158054 | return tmp_non_trans_tables_to_binlog.size() != 0; | |
| 1800 | } | ||
| 1801 | |||
| 1802 | 156464 | bool has_any_nonexistent_tables() const { | |
| 1803 | 156464 | return nonexistent_tables.size() != 0; | |
| 1804 | } | ||
| 1805 | 230007 | bool has_base_nonexistent_tables() const { | |
| 1806 |
4/4✓ Branch 0 taken 208674 times.
✓ Branch 1 taken 21333 times.
✓ Branch 2 taken 17083 times.
✓ Branch 3 taken 191591 times.
|
230007 | return !drop_temporary && nonexistent_tables.size() != 0; |
| 1807 | } | ||
| 1808 | |||
| 1809 | 274102 | bool has_tmp_nonexistent_tables() const { | |
| 1810 |
4/4✓ Branch 0 taken 6641 times.
✓ Branch 1 taken 267461 times.
✓ Branch 2 taken 1492 times.
✓ Branch 3 taken 5149 times.
|
274102 | return drop_temporary && nonexistent_tables.size() != 0; |
| 1811 | } | ||
| 1812 | |||
| 1813 | 243453 | bool has_views() const { return views.size() != 0; } | |
| 1814 | |||
| 1815 | /** | ||
| 1816 | Base tables in SE which do not support atomic DDL which we managed to | ||
| 1817 | drop so far. | ||
| 1818 | */ | ||
| 1819 | Prealloced_array<TABLE_LIST *, 1> dropped_non_atomic; | ||
| 1820 | |||
| 1821 | 6 | bool has_dropped_non_atomic() const { return dropped_non_atomic.size() != 0; } | |
| 1822 | |||
| 1823 | /** | ||
| 1824 | In which situation regarding GTID mode and different types | ||
| 1825 | of tables to be dropped we are. | ||
| 1826 | |||
| 1827 | TODO: consider splitting into 2 orthogonal enum/bools. | ||
| 1828 | */ | ||
| 1829 | enum { | ||
| 1830 | NO_GTID_MANY_TABLE_GROUPS, | ||
| 1831 | NO_GTID_SINGLE_TABLE_GROUP, | ||
| 1832 | GTID_MANY_TABLE_GROUPS, | ||
| 1833 | GTID_SINGLE_TABLE_GROUP | ||
| 1834 | } gtid_and_table_groups_state; | ||
| 1835 | |||
| 1836 | /* Methods to simplify querying the above state. */ | ||
| 1837 | 6915 | bool has_no_gtid_many_table_groups() const { | |
| 1838 | 6915 | return gtid_and_table_groups_state == NO_GTID_MANY_TABLE_GROUPS; | |
| 1839 | } | ||
| 1840 | |||
| 1841 | 107550 | bool has_no_gtid_single_table_group() const { | |
| 1842 | 107550 | return gtid_and_table_groups_state == NO_GTID_SINGLE_TABLE_GROUP; | |
| 1843 | } | ||
| 1844 | |||
| 1845 | 259108 | bool has_gtid_many_table_groups() const { | |
| 1846 | 259108 | return gtid_and_table_groups_state == GTID_MANY_TABLE_GROUPS; | |
| 1847 | } | ||
| 1848 | |||
| 1849 | 10223 | bool has_gtid_single_table_group() const { | |
| 1850 | 10223 | return gtid_and_table_groups_state == GTID_SINGLE_TABLE_GROUP; | |
| 1851 | } | ||
| 1852 | }; | ||
| 1853 | |||
| 1854 | /** | ||
| 1855 | Auxiliary function which appends to the string table identifier with proper | ||
| 1856 | quoting and schema part if necessary. | ||
| 1857 | */ | ||
| 1858 | |||
| 1859 | 125596 | static void append_table_ident(const THD *thd, String *to, | |
| 1860 | const TABLE_LIST *table, bool force_db) { | ||
| 1861 | // Don't write the database name if it is the current one. | ||
| 1862 |
7/8✓ Branch 0 taken 125198 times.
✓ Branch 1 taken 398 times.
✓ Branch 2 taken 123685 times.
✓ Branch 3 taken 1513 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 123685 times.
✓ Branch 6 taken 1911 times.
✓ Branch 7 taken 123685 times.
|
125596 | if (thd->db().str == nullptr || strcmp(table->db, thd->db().str) != 0 || |
| 1863 | force_db) { | ||
| 1864 | 1911 | append_identifier(thd, to, table->db, table->db_length, system_charset_info, | |
| 1865 | thd->charset()); | ||
| 1866 |
1/2✓ Branch 0 taken 1911 times.
✗ Branch 1 not taken.
|
1911 | to->append("."); |
| 1867 | } | ||
| 1868 | 125596 | append_identifier(thd, to, table->table_name, table->table_name_length, | |
| 1869 | system_charset_info, thd->charset()); | ||
| 1870 | 125596 | } | |
| 1871 | |||
| 1872 | /** | ||
| 1873 | Auxiliary function which appends to the string schema and table name for | ||
| 1874 | the table (without quoting). | ||
| 1875 | */ | ||
| 1876 | |||
| 1877 | 12130 | static void append_table_name(String *to, const TABLE_LIST *table) { | |
| 1878 |
1/2✓ Branch 0 taken 12130 times.
✗ Branch 1 not taken.
|
12130 | to->append(String(table->db, system_charset_info)); |
| 1879 | 12130 | to->append('.'); | |
| 1880 |
1/2✓ Branch 0 taken 12130 times.
✗ Branch 1 not taken.
|
12130 | to->append(String(table->table_name, system_charset_info)); |
| 1881 | 12130 | } | |
| 1882 | |||
| 1883 | /** | ||
| 1884 | Auxiliary class which is used to construct synthesized DROP TABLES | ||
| 1885 | statements for the binary log during execution of DROP TABLES statement. | ||
| 1886 | */ | ||
| 1887 | |||
| 1888 | class Drop_tables_query_builder { | ||
| 1889 | public: | ||
| 1890 | 108136 | Drop_tables_query_builder(THD *thd, bool temporary, bool if_exists, | |
| 1891 | bool is_trans, bool no_db) | ||
| 1892 | 108136 | : m_bin_log_is_open(mysql_bin_log.is_open()), | |
| 1893 | 108136 | m_thd(thd), | |
| 1894 | 108136 | m_is_trans(is_trans), | |
| 1895 | 108136 | m_no_db(no_db) { | |
| 1896 |
2/2✓ Branch 0 taken 98209 times.
✓ Branch 1 taken 9927 times.
|
108136 | if (m_bin_log_is_open) { |
| 1897 | 98209 | m_built_query.set_charset(system_charset_info); | |
| 1898 |
1/2✓ Branch 0 taken 98209 times.
✗ Branch 1 not taken.
|
98209 | m_built_query.append("DROP "); |
| 1899 |
3/4✓ Branch 0 taken 1743 times.
✓ Branch 1 taken 96466 times.
✓ Branch 2 taken 1743 times.
✗ Branch 3 not taken.
|
98209 | if (temporary) m_built_query.append("TEMPORARY "); |
| 1900 |
1/2✓ Branch 0 taken 98209 times.
✗ Branch 1 not taken.
|
98209 | m_built_query.append("TABLE "); |
| 1901 |
3/4✓ Branch 0 taken 19211 times.
✓ Branch 1 taken 78998 times.
✓ Branch 2 taken 19211 times.
✗ Branch 3 not taken.
|
98209 | if (if_exists) m_built_query.append("IF EXISTS "); |
| 1902 | } | ||
| 1903 | 108136 | } | |
| 1904 | |||
| 1905 | /* | ||
| 1906 | Constructor for the most common case: | ||
| 1907 | - base tables | ||
| 1908 | - write to binlog trx cache | ||
| 1909 | - Database exists | ||
| 1910 | */ | ||
| 1911 | Drop_tables_query_builder(THD *thd, bool if_exists) | ||
| 1912 | : m_bin_log_is_open(mysql_bin_log.is_open()), | ||
| 1913 | m_thd(thd), | ||
| 1914 | m_is_trans(true), | ||
| 1915 | m_no_db(false) { | ||
| 1916 | if (m_bin_log_is_open) { | ||
| 1917 | m_built_query.set_charset(system_charset_info); | ||
| 1918 | m_built_query.append("DROP TABLE "); | ||
| 1919 | if (if_exists) m_built_query.append("IF EXISTS "); | ||
| 1920 | } | ||
| 1921 | } | ||
| 1922 | |||
| 1923 | private: | ||
| 1924 | 125596 | void add_table_impl(const TABLE_LIST *table) { | |
| 1925 | 125596 | append_table_ident(m_thd, &m_built_query, table, m_no_db); | |
| 1926 |
1/2✓ Branch 0 taken 125596 times.
✗ Branch 1 not taken.
|
125596 | m_built_query.append(","); |
| 1927 | |||
| 1928 | 125596 | m_thd->add_to_binlog_accessed_dbs(table->db); | |
| 1929 | 125596 | } | |
| 1930 | |||
| 1931 | public: | ||
| 1932 | 36080 | void add_table(const TABLE_LIST *table) { | |
| 1933 |
2/2✓ Branch 0 taken 26682 times.
✓ Branch 1 taken 9398 times.
|
36080 | if (m_bin_log_is_open) add_table_impl(table); |
| 1934 | 36080 | } | |
| 1935 | |||
| 1936 | 143782 | void add_array(const Prealloced_array<TABLE_LIST *, 1> &tables) { | |
| 1937 |
2/2✓ Branch 0 taken 142726 times.
✓ Branch 1 taken 1056 times.
|
143782 | if (m_bin_log_is_open) { |
| 1938 |
2/2✓ Branch 0 taken 98914 times.
✓ Branch 1 taken 142726 times.
|
241640 | for (TABLE_LIST *table : tables) add_table_impl(table); |
| 1939 | } | ||
| 1940 | 143782 | } | |
| 1941 | |||
| 1942 | 94288 | bool write_bin_log() { | |
| 1943 |
2/2✓ Branch 0 taken 84670 times.
✓ Branch 1 taken 9618 times.
|
94288 | if (m_bin_log_is_open) { |
| 1944 | /* Chop off the last comma */ | ||
| 1945 | 84670 | m_built_query.chop(); | |
| 1946 |
1/2✓ Branch 0 taken 84670 times.
✗ Branch 1 not taken.
|
84670 | m_built_query.append(" /* generated by server */"); |
| 1947 | |||
| 1948 | /* | ||
| 1949 | We can't use ::write_bin_log() here as this method is sometimes used | ||
| 1950 | in case when DROP TABLES statement is supposed to report an error. | ||
| 1951 | And ::write_bin_log() either resets error in DA or uses it for binlog | ||
| 1952 | event (which we would like to avoid too). | ||
| 1953 | */ | ||
| 1954 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 84668 times.
|
84670 | if (m_thd->binlog_query(THD::STMT_QUERY_TYPE, m_built_query.ptr(), |
| 1955 | 84670 | m_built_query.length(), m_is_trans, | |
| 1956 | 84670 | false /* direct */, m_no_db /* suppress_use */, | |
| 1957 | 0 /* errcode */)) | ||
| 1958 | 2 | return true; | |
| 1959 | } | ||
| 1960 | 94286 | return false; | |
| 1961 | } | ||
| 1962 | |||
| 1963 | private: | ||
| 1964 | bool m_bin_log_is_open; | ||
| 1965 | THD *m_thd; | ||
| 1966 | bool m_is_trans; | ||
| 1967 | bool m_no_db; | ||
| 1968 | String m_built_query; | ||
| 1969 | }; | ||
| 1970 | |||
| 1971 | /** | ||
| 1972 | Auxiliary function which prepares for DROP TABLES execution by sorting | ||
| 1973 | tables to be dropped into groups according to their types. | ||
| 1974 | */ | ||
| 1975 | |||
| 1976 | 156486 | static bool rm_table_sort_into_groups(THD *thd, Drop_tables_ctx *drop_ctx, | |
| 1977 | TABLE_LIST *tables) { | ||
| 1978 | /* | ||
| 1979 | Sort tables into groups according to type of handling they require: | ||
| 1980 | |||
| 1981 | 1) Base tables and views. Further divided into the following groups: | ||
| 1982 | |||
| 1983 | a) Base tables in storage engines which don't support atomic DDL. | ||
| 1984 | |||
| 1985 | Their drop can't be rolled back in case of crash or error. | ||
| 1986 | So we drop each such table individually and write to binlog | ||
| 1987 | a single-table DROP TABLE statement corresponding to this | ||
| 1988 | action right after it. This increases chances of SE, | ||
| 1989 | data-dictionary and binary log being in sync if crash occurs. | ||
| 1990 | This also handles case of error/statement being killed in | ||
| 1991 | a natural way - by the time when error occurs we already | ||
| 1992 | have logged all drops which were successful. So we don't | ||
| 1993 | need to write the whole failed statement with error code | ||
| 1994 | to binary log. | ||
| 1995 | |||
| 1996 | b) Base tables in SEs which support atomic DDL. | ||
| 1997 | |||
| 1998 | Their drop can be rolled back, so we drop them in SE, remove | ||
| 1999 | from data-dictionary and write corresponding statement to the | ||
| 2000 | binary log in one atomic transaction all together. | ||
| 2001 | |||
| 2002 | c) Views. | ||
| 2003 | |||
| 2004 | Have to be dropped when this function is called as part of | ||
| 2005 | DROP DATABASE implementation. Dropping them requires | ||
| 2006 | data-dictionary update only, so can be done atomically | ||
| 2007 | with b). | ||
| 2008 | |||
| 2009 | d) Non-existent tables. | ||
| 2010 | |||
| 2011 | In the absence of IF EXISTS clause cause statement failure. | ||
| 2012 | We do this check before dropping any tables to get nice atomic | ||
| 2013 | behavior for most common failure scenario even for tables which | ||
| 2014 | don't support atomic DDL. | ||
| 2015 | |||
| 2016 | When IF EXISTS clause is present notes are generated instead of | ||
| 2017 | error. We assume that non-existing tables support atomic DDL and | ||
| 2018 | write such tables to binary log together with tables from group b) | ||
| 2019 | (after all no-op can be rolled back!) to get a nice single DROP | ||
| 2020 | TABLES statement in the binlog in the default use-case. It is not | ||
| 2021 | a big problem if this assumption turns out to be false on slave. | ||
| 2022 | The statement still will be applied correctly (but crash-safeness | ||
| 2023 | will be sacrificed). | ||
| 2024 | |||
| 2025 | 2) Temporary tables. | ||
| 2026 | |||
| 2027 | To avoid problems due to shadowing base tables should be always | ||
| 2028 | binlogged as DROP TEMPORARY TABLE. | ||
| 2029 | |||
| 2030 | Their drop can't be rolled back even for transactional SEs, on the | ||
| 2031 | other hand it can't fail once first simple checks are done. So it | ||
| 2032 | makes sense to drop them after base tables. | ||
| 2033 | |||
| 2034 | Unlike for base tables, it is possible to drop database in which some | ||
| 2035 | connection has temporary tables open. So we can end-up in situation | ||
| 2036 | when connection's default database is no more, but still the connection | ||
| 2037 | has some temporary tables in it. It is possible to drop such tables, | ||
| 2038 | but we should be careful when binlogging such drop. | ||
| 2039 | Using "USE db_which_is_no_more;" before DROP TEMPORARY TABLES will | ||
| 2040 | break replication. | ||
| 2041 | |||
| 2042 | Temporary tables are further divided into the following groups: | ||
| 2043 | |||
| 2044 | a) Temporary tables in non-transactional SE | ||
| 2045 | b) Temporary tables in transactional SE | ||
| 2046 | |||
| 2047 | DROP TEMPORARY TABLES does not commit an ongoing transaction. So in | ||
| 2048 | some circumstances we must binlog changes to non-transactional tables | ||
| 2049 | ahead of transaction, while changes to transactional tables should be | ||
| 2050 | binlogged as part of transaction. | ||
| 2051 | |||
| 2052 | c) Non-existent temporary tables. | ||
| 2053 | |||
| 2054 | Can be non-empty only if DROP TEMPORARY TABLES was used (otherwise | ||
| 2055 | all non-existent tables go to group 1.d)). | ||
| 2056 | |||
| 2057 | Similarly to group 1.d) if IF EXISTS clause is absent causes | ||
| 2058 | statement failure. Otherwise note is generated for each such table. | ||
| 2059 | |||
| 2060 | The non-existing temporary tables are logged together with | ||
| 2061 | transactional ones (group 2.b)), if any transactional tables exist | ||
| 2062 | or if there is only non-existing tables; otherwise are logged | ||
| 2063 | together with non-transactional ones (group 2.a)). | ||
| 2064 | |||
| 2065 | This logic ensures that: | ||
| 2066 | - On master, transactional and non-transactional tables are | ||
| 2067 | written to different statements. | ||
| 2068 | - Therefore, slave will never see statements containing both | ||
| 2069 | transactional and non-transactional temporary tables. | ||
| 2070 | - Since non-existing temporary tables are logged together with | ||
| 2071 | whatever type of temporary tables that exist, the slave thus | ||
| 2072 | writes any statement as just one statement. I.e., the slave | ||
| 2073 | never splits a statement into two. This is crucial when GTIDs | ||
| 2074 | are enabled, since otherwise the statement, which already has | ||
| 2075 | a GTID, would need two different GTIDs. | ||
| 2076 | */ | ||
| 2077 |
2/2✓ Branch 0 taken 196612 times.
✓ Branch 1 taken 156480 times.
|
353092 | for (TABLE_LIST *table = tables; table; table = table->next_local) { |
| 2078 | /* | ||
| 2079 | Check THD::killed flag, so we can abort potentially lengthy loop. | ||
| 2080 | This can be relevant for DROP DATABASE, for example. | ||
| 2081 | */ | ||
| 2082 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 196607 times.
|
196613 | if (thd->killed) return true; |
| 2083 | |||
| 2084 |
2/2✓ Branch 0 taken 185505 times.
✓ Branch 1 taken 11102 times.
|
196607 | if (table->open_type != OT_BASE_ONLY) { |
| 2085 | /* DROP DATABASE doesn't deal with temporary tables. */ | ||
| 2086 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 185505 times.
|
185505 | assert(!drop_ctx->drop_database); |
| 2087 | |||
| 2088 |
2/2✓ Branch 0 taken 135635 times.
✓ Branch 1 taken 49870 times.
|
185505 | if (!is_temporary_table(table)) { |
| 2089 | // A temporary table was not found. | ||
| 2090 |
2/2✓ Branch 0 taken 847 times.
✓ Branch 1 taken 134788 times.
|
135635 | if (drop_ctx->drop_temporary) { |
| 2091 |
1/2✓ Branch 0 taken 847 times.
✗ Branch 1 not taken.
|
847 | drop_ctx->nonexistent_tables.push_back(table); |
| 2092 | 50717 | continue; | |
| 2093 | } | ||
| 2094 | /* | ||
| 2095 | Not DROP TEMPORARY and no matching temporary table. | ||
| 2096 | Continue with base tables. | ||
| 2097 | */ | ||
| 2098 | } else { | ||
| 2099 | /* | ||
| 2100 | A temporary table was found and can be successfully dropped. | ||
| 2101 | |||
| 2102 | The fact that this temporary table is used by an outer statement | ||
| 2103 | should be detected and reported as error earlier. | ||
| 2104 | */ | ||
| 2105 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 49870 times.
|
49870 | assert(table->table->query_id == thd->query_id); |
| 2106 | |||
| 2107 |
2/2✓ Branch 0 taken 43852 times.
✓ Branch 1 taken 6018 times.
|
49870 | if (table->table->file->has_transactions()) { |
| 2108 |
1/2✓ Branch 0 taken 43852 times.
✗ Branch 1 not taken.
|
43852 | drop_ctx->tmp_trans_tables.push_back(table); |
| 2109 |
3/4✓ Branch 0 taken 43852 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1092 times.
✓ Branch 3 taken 42760 times.
|
43852 | if (table->table->should_binlog_drop_if_temp()) |
| 2110 |
1/2✓ Branch 0 taken 1092 times.
✗ Branch 1 not taken.
|
1092 | drop_ctx->tmp_trans_tables_to_binlog.push_back(table); |
| 2111 | } else { | ||
| 2112 |
1/2✓ Branch 0 taken 6018 times.
✗ Branch 1 not taken.
|
6018 | drop_ctx->tmp_non_trans_tables.push_back(table); |
| 2113 |
3/4✓ Branch 0 taken 6018 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 821 times.
✓ Branch 3 taken 5197 times.
|
6018 | if (table->table->should_binlog_drop_if_temp()) |
| 2114 |
1/2✓ Branch 0 taken 821 times.
✗ Branch 1 not taken.
|
821 | drop_ctx->tmp_non_trans_tables_to_binlog.push_back(table); |
| 2115 | } | ||
| 2116 | 49870 | continue; | |
| 2117 | } | ||
| 2118 | } | ||
| 2119 | |||
| 2120 | /* We should not try to drop active log tables. Callers enforce this. */ | ||
| 2121 |
2/4✓ Branch 0 taken 145890 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 145890 times.
|
145890 | assert(query_logger.check_if_log_table(table, true) == QUERY_LOG_NONE); |
| 2122 | |||
| 2123 |
1/2✓ Branch 0 taken 145890 times.
✗ Branch 1 not taken.
|
145890 | dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client()); |
| 2124 | 145890 | const dd::Abstract_table *abstract_table_def = nullptr; | |
| 2125 |
4/8✓ Branch 0 taken 145890 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 145890 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 145890 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 145890 times.
|
145890 | if (thd->dd_client()->acquire(table->db, table->table_name, |
| 2126 | &abstract_table_def)) { | ||
| 2127 | /* Error should have been reported by data-dictionary subsystem. */ | ||
| 2128 | ✗ | return true; | |
| 2129 | } | ||
| 2130 | |||
| 2131 |
2/2✓ Branch 0 taken 11259 times.
✓ Branch 1 taken 134631 times.
|
145890 | if (!abstract_table_def) |
| 2132 |
1/2✓ Branch 0 taken 11259 times.
✗ Branch 1 not taken.
|
11259 | drop_ctx->nonexistent_tables.push_back(table); |
| 2133 |
3/4✓ Branch 0 taken 134631 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 133764 times.
✓ Branch 3 taken 867 times.
|
134631 | else if (abstract_table_def->type() == dd::enum_table_type::BASE_TABLE) { |
| 2134 | const dd::Table *table_def = | ||
| 2135 |
1/2✓ Branch 0 taken 133764 times.
✗ Branch 1 not taken.
|
133764 | dynamic_cast<const dd::Table *>(abstract_table_def); |
| 2136 | |||
| 2137 | 133764 | handlerton *hton{nullptr}; | |
| 2138 |
3/4✓ Branch 0 taken 133764 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 133763 times.
|
133764 | if (dd::table_storage_engine(thd, table_def, &hton)) return true; |
| 2139 | |||
| 2140 | /* | ||
| 2141 | We don't have SEs which support FKs and don't support atomic DDL. | ||
| 2142 | If we ever to support such engines we need to adjust code that checks | ||
| 2143 | if we can drop parent table to correctly handle such SEs. | ||
| 2144 | */ | ||
| 2145 |
3/4✓ Branch 0 taken 96469 times.
✓ Branch 1 taken 37294 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 96469 times.
|
133763 | assert(!(hton->flags & HTON_SUPPORTS_FOREIGN_KEYS) || |
| 2146 | (hton->flags & HTON_SUPPORTS_ATOMIC_DDL)); | ||
| 2147 | |||
| 2148 |
5/6✓ Branch 0 taken 37294 times.
✓ Branch 1 taken 96469 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 37294 times.
✓ Branch 4 taken 96469 times.
✓ Branch 5 taken 37294 times.
|
133763 | if (hton->flags & HTON_SUPPORTS_ATOMIC_DDL || thd->is_plugin_fake_ddl()) |
| 2149 |
1/2✓ Branch 0 taken 96469 times.
✗ Branch 1 not taken.
|
96469 | drop_ctx->base_atomic_tables.push_back(table); |
| 2150 | else | ||
| 2151 |
1/2✓ Branch 0 taken 37294 times.
✗ Branch 1 not taken.
|
37294 | drop_ctx->base_non_atomic_tables.push_back(table); |
| 2152 | } else // View | ||
| 2153 | { | ||
| 2154 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 861 times.
|
867 | if (!drop_ctx->drop_database) { |
| 2155 | /* | ||
| 2156 | Historically, DROP TABLES treats situation when we have a view | ||
| 2157 | instead of table to be dropped as non-existent table. | ||
| 2158 | */ | ||
| 2159 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | drop_ctx->nonexistent_tables.push_back(table); |
| 2160 | } else | ||
| 2161 |
1/2✓ Branch 0 taken 861 times.
✗ Branch 1 not taken.
|
861 | drop_ctx->views.push_back(table); |
| 2162 | } | ||
| 2163 |
2/2✓ Branch 0 taken 145889 times.
✓ Branch 1 taken 1 times.
|
145890 | } |
| 2164 | |||
| 2165 | 156480 | return false; | |
| 2166 | } | ||
| 2167 | |||
| 2168 | /** | ||
| 2169 | Auxiliary function which evaluates in which situation DROP TABLES | ||
| 2170 | is regarding GTID and different table groups. | ||
| 2171 | */ | ||
| 2172 | |||
| 2173 | 156480 | static bool rm_table_eval_gtid_and_table_groups_state( | |
| 2174 | THD *thd, Drop_tables_ctx *drop_ctx) { | ||
| 2175 |
2/2✓ Branch 0 taken 2041 times.
✓ Branch 1 taken 154439 times.
|
156480 | if (thd->variables.gtid_next.type == ASSIGNED_GTID) { |
| 2176 | /* | ||
| 2177 | This statement has been assigned GTID. | ||
| 2178 | |||
| 2179 | In this case we need to take special care about group handling | ||
| 2180 | and commits, as statement can't be logged/split into several | ||
| 2181 | statements in this case. | ||
| 2182 | |||
| 2183 | Three different situations are possible in this case: | ||
| 2184 | - "normal" when we have one GTID assigned and one group | ||
| 2185 | to go as single statement to binary logs | ||
| 2186 | - "prohibited" when we have one GTID assigned and two | ||
| 2187 | kinds of temporary tables or mix of temporary and | ||
| 2188 | base tables | ||
| 2189 | - "awkward" when we have one GTID but several groups or | ||
| 2190 | several tables in non-atomic base group (1.a). | ||
| 2191 | */ | ||
| 2192 | |||
| 2193 |
2/2✓ Branch 0 taken 48 times.
✓ Branch 1 taken 1993 times.
|
2041 | if (drop_ctx->drop_database) { |
| 2194 | /* DROP DATABASE doesn't drop any temporary tables. */ | ||
| 2195 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
|
48 | assert(!drop_ctx->has_tmp_trans_tables()); |
| 2196 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
|
48 | assert(!drop_ctx->has_tmp_non_trans_tables()); |
| 2197 | |||
| 2198 |
2/2✓ Branch 0 taken 42 times.
✓ Branch 1 taken 6 times.
|
48 | if (!drop_ctx->has_base_non_atomic_tables()) { |
| 2199 | /* | ||
| 2200 | Normal case. This is DROP DATABASE and we don't have any tables in | ||
| 2201 | SEs which don't support atomic DDL. Remaining tables, views, | ||
| 2202 | routines and events can be dropped atomically and atomically logged | ||
| 2203 | as a single DROP DATABASE statement by the caller. | ||
| 2204 | */ | ||
| 2205 | 42 | drop_ctx->gtid_and_table_groups_state = | |
| 2206 | Drop_tables_ctx::GTID_SINGLE_TABLE_GROUP; | ||
| 2207 | } else { | ||
| 2208 | /* | ||
| 2209 | Awkward case. We have GTID assigned for DROP DATABASE and it needs | ||
| 2210 | to drop table in SE which doesn't support atomic DDL. | ||
| 2211 | |||
| 2212 | Most probably we are replicating from older (pre-5.8) master or tables | ||
| 2213 | on master and slave have different SEs. | ||
| 2214 | We try to handle situation in the following way - if the whole | ||
| 2215 | statement succeeds caller will log all changes as a single DROP | ||
| 2216 | DATABASE under GTID provided. In case of failure we will emit special | ||
| 2217 | error saying that statement can't be logged correctly and manual | ||
| 2218 | intervention is required. | ||
| 2219 | */ | ||
| 2220 | 6 | drop_ctx->gtid_and_table_groups_state = | |
| 2221 | Drop_tables_ctx::GTID_MANY_TABLE_GROUPS; | ||
| 2222 | } | ||
| 2223 | } else { | ||
| 2224 | /* Only DROP DATABASE drops views. */ | ||
| 2225 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1993 times.
|
1993 | assert(!drop_ctx->has_views()); |
| 2226 | |||
| 2227 | 1993 | if ((drop_ctx->has_tmp_trans_tables_to_binlog() && | |
| 2228 |
6/6✓ Branch 0 taken 30 times.
✓ Branch 1 taken 1963 times.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 1987 times.
|
3984 | drop_ctx->has_tmp_non_trans_tables_to_binlog()) || |
| 2229 |
2/2✓ Branch 0 taken 1836 times.
✓ Branch 1 taken 155 times.
|
1991 | ((drop_ctx->has_base_non_atomic_tables() || |
| 2230 |
2/2✓ Branch 0 taken 419 times.
✓ Branch 1 taken 1417 times.
|
1836 | drop_ctx->has_base_atomic_tables() || |
| 2231 |
2/2✓ Branch 0 taken 20 times.
✓ Branch 1 taken 399 times.
|
419 | drop_ctx->has_base_nonexistent_tables()) && |
| 2232 |
2/2✓ Branch 0 taken 1589 times.
✓ Branch 1 taken 3 times.
|
1592 | (drop_ctx->has_tmp_trans_tables_to_binlog() || |
| 2233 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1588 times.
|
1589 | drop_ctx->has_tmp_non_trans_tables_to_binlog()))) { |
| 2234 | /* | ||
| 2235 | Prohibited case. We have either both kinds of temporary tables or | ||
| 2236 | mix of non-temporary and temporary tables. | ||
| 2237 | |||
| 2238 | Normally, such DROP TEMPORARY TABLES or DROP TABLES statements are | ||
| 2239 | written into the binary log at least in two pieces. This is, of | ||
| 2240 | course, impossible with a single GTID assigned. | ||
| 2241 | |||
| 2242 | Executing such statements with a GTID assigned is prohibited at | ||
| 2243 | least since 5.7, so should not create new problems with backward | ||
| 2244 | compatibility and cross-version replication. | ||
| 2245 | |||
| 2246 | (Writing deletion of different kinds of temporary and/or base tables | ||
| 2247 | as single multi-table DROP TABLES under single GTID might be | ||
| 2248 | theoretically possible in some cases, but has its own problems). | ||
| 2249 | */ | ||
| 2250 | 6 | my_error(ER_GTID_UNSAFE_BINLOG_SPLITTABLE_STATEMENT_AND_ASSIGNED_GTID, | |
| 2251 | MYF(0)); | ||
| 2252 | 6 | return true; | |
| 2253 | } | ||
| 2254 | 1987 | if (drop_ctx->base_non_atomic_tables.size() == 1 && | |
| 2255 |
6/6✓ Branch 0 taken 149 times.
✓ Branch 1 taken 1838 times.
✓ Branch 2 taken 141 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 140 times.
✓ Branch 5 taken 1847 times.
|
2128 | !drop_ctx->has_base_atomic_tables() && |
| 2256 |
2/2✓ Branch 0 taken 140 times.
✓ Branch 1 taken 1 times.
|
141 | !drop_ctx->has_base_nonexistent_tables()) { |
| 2257 | /* | ||
| 2258 | Normal case. Single base table in SE which don't support atomic DDL | ||
| 2259 | so it will be logged as a single-table DROP TABLES statement. | ||
| 2260 | We still can have temporary tables in this drop, but only those ones | ||
| 2261 | which are not logged (previous 'if' would detect them). | ||
| 2262 | Such temporary tables will be just dropped, but not logged. | ||
| 2263 | */ | ||
| 2264 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 140 times.
|
140 | assert(!drop_ctx->has_tmp_trans_tables_to_binlog()); |
| 2265 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 140 times.
|
140 | assert(!drop_ctx->has_tmp_non_trans_tables_to_binlog()); |
| 2266 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 140 times.
|
140 | assert(!drop_ctx->has_tmp_nonexistent_tables()); |
| 2267 | 140 | drop_ctx->gtid_and_table_groups_state = | |
| 2268 | Drop_tables_ctx::GTID_SINGLE_TABLE_GROUP; | ||
| 2269 | 1847 | } else if ((drop_ctx->has_base_atomic_tables() || | |
| 2270 |
6/6✓ Branch 0 taken 421 times.
✓ Branch 1 taken 1426 times.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 400 times.
✓ Branch 4 taken 1435 times.
✓ Branch 5 taken 412 times.
|
3294 | drop_ctx->has_base_nonexistent_tables()) && |
| 2271 |
2/2✓ Branch 0 taken 1435 times.
✓ Branch 1 taken 12 times.
|
1447 | !drop_ctx->has_base_non_atomic_tables()) { |
| 2272 | /* | ||
| 2273 | Normal case. Several base tables which can be dropped atomically. | ||
| 2274 | Can be logged as one atomic multi-table DROP TABLES statement. | ||
| 2275 | Other groups are empty. | ||
| 2276 | */ | ||
| 2277 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1435 times.
|
1435 | assert(!drop_ctx->has_tmp_trans_tables_to_binlog()); |
| 2278 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1435 times.
|
1435 | assert(!drop_ctx->has_tmp_non_trans_tables_to_binlog()); |
| 2279 | 1435 | drop_ctx->gtid_and_table_groups_state = | |
| 2280 | Drop_tables_ctx::GTID_SINGLE_TABLE_GROUP; | ||
| 2281 |
4/4✓ Branch 0 taken 215 times.
✓ Branch 1 taken 197 times.
✓ Branch 2 taken 229 times.
✓ Branch 3 taken 183 times.
|
627 | } else if (drop_ctx->has_tmp_trans_tables() || |
| 2282 |
2/2✓ Branch 0 taken 45 times.
✓ Branch 1 taken 170 times.
|
215 | (!drop_ctx->has_tmp_non_trans_tables() && |
| 2283 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 13 times.
|
45 | drop_ctx->has_tmp_nonexistent_tables())) { |
| 2284 | /* | ||
| 2285 | Normal case. Some temporary transactional tables (and/or possibly | ||
| 2286 | some non-existent temporary tables) to be logged as one multi-table | ||
| 2287 | DROP TEMPORARY TABLES statement. | ||
| 2288 | Other groups are empty. | ||
| 2289 | */ | ||
| 2290 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 229 times.
|
229 | assert(!drop_ctx->has_base_non_atomic_tables()); |
| 2291 |
2/4✓ Branch 0 taken 229 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 229 times.
✗ Branch 3 not taken.
|
229 | assert(!drop_ctx->has_base_atomic_tables() && |
| 2292 | !drop_ctx->has_base_nonexistent_tables()); | ||
| 2293 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 229 times.
|
229 | assert(!drop_ctx->has_tmp_non_trans_tables_to_binlog()); |
| 2294 | 229 | drop_ctx->gtid_and_table_groups_state = | |
| 2295 | Drop_tables_ctx::GTID_SINGLE_TABLE_GROUP; | ||
| 2296 |
2/2✓ Branch 0 taken 170 times.
✓ Branch 1 taken 13 times.
|
183 | } else if (drop_ctx->has_tmp_non_trans_tables()) { |
| 2297 | /* | ||
| 2298 | Normal case. Some temporary non-transactional tables (and possibly | ||
| 2299 | some non-existent temporary tables) to be logged as one multi-table | ||
| 2300 | DROP TEMPORARY TABLES statement. | ||
| 2301 | Other groups are empty. | ||
| 2302 | */ | ||
| 2303 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 170 times.
|
170 | assert(!drop_ctx->has_base_non_atomic_tables()); |
| 2304 |
2/4✓ Branch 0 taken 170 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 170 times.
✗ Branch 3 not taken.
|
170 | assert(!drop_ctx->has_base_atomic_tables() && |
| 2305 | !drop_ctx->has_base_nonexistent_tables()); | ||
| 2306 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 170 times.
|
170 | assert(!drop_ctx->has_tmp_trans_tables()); |
| 2307 | 170 | drop_ctx->gtid_and_table_groups_state = | |
| 2308 | Drop_tables_ctx::GTID_SINGLE_TABLE_GROUP; | ||
| 2309 | } else { | ||
| 2310 | /* | ||
| 2311 | Awkward case. We have several tables from non-atomic group 1.a, or | ||
| 2312 | tables from both atomic (1.b, 1.c, 1.d) and non-atomic groups. | ||
| 2313 | |||
| 2314 | Most probably we are replicating from older (pre-5.8) master or tables | ||
| 2315 | on master and slave have different SEs. | ||
| 2316 | We try to handle this situation gracefully by writing single | ||
| 2317 | multi-table DROP TABLES statement including tables from all groups | ||
| 2318 | under GTID provided. Of course this means that we are not crash-safe | ||
| 2319 | in this case. But we can't be fully crash-safe in cases when | ||
| 2320 | non-atomic tables are involved anyway. | ||
| 2321 | |||
| 2322 | Note that temporary tables groups still should be empty in this case. | ||
| 2323 | */ | ||
| 2324 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
|
13 | assert(!drop_ctx->has_tmp_trans_tables()); |
| 2325 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
|
13 | assert(!drop_ctx->has_tmp_non_trans_tables()); |
| 2326 | 13 | drop_ctx->gtid_and_table_groups_state = | |
| 2327 | Drop_tables_ctx::GTID_MANY_TABLE_GROUPS; | ||
| 2328 | } | ||
| 2329 | } | ||
| 2330 | } else { | ||
| 2331 | /* | ||
| 2332 | This statement has no GTID assigned. We can handle any mix of | ||
| 2333 | groups in this case. However full atomicity is guaranteed only | ||
| 2334 | in certain scenarios. | ||
| 2335 | */ | ||
| 2336 | |||
| 2337 |
2/2✓ Branch 0 taken 3170 times.
✓ Branch 1 taken 151269 times.
|
154439 | if (drop_ctx->drop_database) { |
| 2338 | /* DROP DATABASE doesn't drop any temporary tables. */ | ||
| 2339 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3170 times.
|
3170 | assert(!drop_ctx->has_tmp_trans_tables()); |
| 2340 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3170 times.
|
3170 | assert(!drop_ctx->has_tmp_non_trans_tables()); |
| 2341 | |||
| 2342 |
2/2✓ Branch 0 taken 2741 times.
✓ Branch 1 taken 429 times.
|
3170 | if (!drop_ctx->has_base_non_atomic_tables()) { |
| 2343 | /* | ||
| 2344 | Fully atomic case. This is DROP DATABASE and we don't have any | ||
| 2345 | tables in SEs which don't support atomic DDL. Remaining tables, | ||
| 2346 | views, routines and events can be dropped atomically and atomically | ||
| 2347 | logged as a single DROP DATABASE statement by the caller. | ||
| 2348 | */ | ||
| 2349 | 2741 | drop_ctx->gtid_and_table_groups_state = | |
| 2350 | Drop_tables_ctx::NO_GTID_SINGLE_TABLE_GROUP; | ||
| 2351 | } else { | ||
| 2352 | /* | ||
| 2353 | Non-atomic case. This is DROP DATABASE which needs to drop some | ||
| 2354 | tables in SE which doesn't support atomic DDL. To improve | ||
| 2355 | crash-safety we log separate DROP TABLE IF EXISTS for each such | ||
| 2356 | table dropped. Remaining tables, views, routines and events are | ||
| 2357 | dropped atomically and atomically logged as a single DROP DATABASE | ||
| 2358 | statement by the caller. | ||
| 2359 | */ | ||
| 2360 | 429 | drop_ctx->gtid_and_table_groups_state = | |
| 2361 | Drop_tables_ctx::NO_GTID_MANY_TABLE_GROUPS; | ||
| 2362 | } | ||
| 2363 | } else { | ||
| 2364 | /* Only DROP DATABASE drops views. */ | ||
| 2365 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 151269 times.
|
151269 | assert(!drop_ctx->has_views()); |
| 2366 | |||
| 2367 | 151269 | if (drop_ctx->base_non_atomic_tables.size() == 1 && | |
| 2368 |
2/2✓ Branch 0 taken 31567 times.
✓ Branch 1 taken 176 times.
|
31743 | !drop_ctx->has_base_atomic_tables() && |
| 2369 |
2/2✓ Branch 0 taken 31494 times.
✓ Branch 1 taken 73 times.
|
31567 | !drop_ctx->has_base_nonexistent_tables() && |
| 2370 |
6/6✓ Branch 0 taken 31743 times.
✓ Branch 1 taken 119526 times.
✓ Branch 2 taken 31485 times.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 31480 times.
✓ Branch 5 taken 119789 times.
|
214497 | !drop_ctx->has_tmp_trans_tables() && |
| 2371 |
2/2✓ Branch 0 taken 31480 times.
✓ Branch 1 taken 5 times.
|
31485 | !drop_ctx->has_tmp_non_trans_tables()) { |
| 2372 | /* | ||
| 2373 | Simple non-atomic case. Single base table in SE which don't | ||
| 2374 | support atomic DDL so it will be logged as a single-table | ||
| 2375 | DROP TABLES statement. Other groups are empty. | ||
| 2376 | */ | ||
| 2377 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 31480 times.
|
31480 | assert(!drop_ctx->has_tmp_nonexistent_tables()); |
| 2378 | 31480 | drop_ctx->gtid_and_table_groups_state = | |
| 2379 | Drop_tables_ctx::NO_GTID_SINGLE_TABLE_GROUP; | ||
| 2380 | 119789 | } else if ((drop_ctx->has_base_atomic_tables() || | |
| 2381 |
2/2✓ Branch 0 taken 8941 times.
✓ Branch 1 taken 49935 times.
|
58876 | drop_ctx->has_base_nonexistent_tables()) && |
| 2382 |
2/2✓ Branch 0 taken 69245 times.
✓ Branch 1 taken 609 times.
|
69854 | !drop_ctx->has_base_non_atomic_tables() && |
| 2383 |
6/6✓ Branch 0 taken 58876 times.
✓ Branch 1 taken 60913 times.
✓ Branch 2 taken 68570 times.
✓ Branch 3 taken 675 times.
✓ Branch 4 taken 68561 times.
✓ Branch 5 taken 51228 times.
|
308148 | !drop_ctx->has_tmp_trans_tables() && |
| 2384 |
2/2✓ Branch 0 taken 68561 times.
✓ Branch 1 taken 9 times.
|
68570 | !drop_ctx->has_tmp_non_trans_tables()) { |
| 2385 | /* | ||
| 2386 | Fully atomic case. Several base tables which can be dropped | ||
| 2387 | atomically. Can be logged as one atomic multi-table DROP TABLES | ||
| 2388 | statement. Other groups are empty. | ||
| 2389 | */ | ||
| 2390 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 68561 times.
|
68561 | assert(!drop_ctx->has_tmp_nonexistent_tables()); |
| 2391 | 68561 | drop_ctx->gtid_and_table_groups_state = | |
| 2392 | Drop_tables_ctx::NO_GTID_SINGLE_TABLE_GROUP; | ||
| 2393 | 51228 | } else if (!drop_ctx->has_base_non_atomic_tables() && | |
| 2394 |
6/6✓ Branch 0 taken 49422 times.
✓ Branch 1 taken 1806 times.
✓ Branch 2 taken 48738 times.
✓ Branch 3 taken 684 times.
✓ Branch 4 taken 48738 times.
✓ Branch 5 taken 2490 times.
|
99966 | !drop_ctx->has_base_atomic_tables() && |
| 2395 |
1/2✓ Branch 0 taken 48738 times.
✗ Branch 1 not taken.
|
48738 | !drop_ctx->has_base_nonexistent_tables()) { |
| 2396 | /* No base tables to be dropped. */ | ||
| 2397 |
4/4✓ Branch 0 taken 42781 times.
✓ Branch 1 taken 5957 times.
✓ Branch 2 taken 35 times.
✓ Branch 3 taken 48703 times.
|
91519 | if (drop_ctx->has_tmp_trans_tables() && |
| 2398 |
2/2✓ Branch 0 taken 35 times.
✓ Branch 1 taken 42746 times.
|
42781 | drop_ctx->has_tmp_non_trans_tables()) { |
| 2399 | /* | ||
| 2400 | Complex case with temporary tables. We have both transactional | ||
| 2401 | and non-transactional temporary tables and no base tables at all. | ||
| 2402 | |||
| 2403 | We will log separate DROP TEMPORARY TABLES statements for each of | ||
| 2404 | two groups. | ||
| 2405 | */ | ||
| 2406 | 35 | drop_ctx->gtid_and_table_groups_state = | |
| 2407 | Drop_tables_ctx::NO_GTID_MANY_TABLE_GROUPS; | ||
| 2408 | } else { | ||
| 2409 | /* | ||
| 2410 | Simple case with temporary tables. We have either only | ||
| 2411 | transactional or non-transactional temporary tables. | ||
| 2412 | Possibly some non-existent temporary tables. | ||
| 2413 | |||
| 2414 | We can log our statement as a single DROP TEMPORARY TABLES | ||
| 2415 | statement. | ||
| 2416 | */ | ||
| 2417 |
9/14✓ Branch 0 taken 42746 times.
✓ Branch 1 taken 5957 times.
✓ Branch 2 taken 42746 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5957 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5247 times.
✓ Branch 7 taken 710 times.
✓ Branch 8 taken 710 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 710 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 710 times.
✗ Branch 13 not taken.
|
48703 | assert((drop_ctx->has_tmp_trans_tables() && |
| 2418 | !drop_ctx->has_tmp_non_trans_tables()) || | ||
| 2419 | (!drop_ctx->has_tmp_trans_tables() && | ||
| 2420 | drop_ctx->has_tmp_non_trans_tables()) || | ||
| 2421 | (!drop_ctx->has_tmp_trans_tables() && | ||
| 2422 | !drop_ctx->has_tmp_non_trans_tables() && | ||
| 2423 | drop_ctx->has_tmp_nonexistent_tables())); | ||
| 2424 | 48703 | drop_ctx->gtid_and_table_groups_state = | |
| 2425 | Drop_tables_ctx::NO_GTID_SINGLE_TABLE_GROUP; | ||
| 2426 | } | ||
| 2427 | } else { | ||
| 2428 | /* | ||
| 2429 | Complex non-atomic case. We have several tables from non-atomic | ||
| 2430 | group 1.a, or tables from both atomic (1.b, 1.c, 1.d) and non-atomic | ||
| 2431 | groups, or mix of base and temporary tables. | ||
| 2432 | |||
| 2433 | Our statement will be written to binary log as several DROP TABLES and | ||
| 2434 | DROP TEMPORARY TABLES statements. | ||
| 2435 | */ | ||
| 2436 | 2490 | drop_ctx->gtid_and_table_groups_state = | |
| 2437 | Drop_tables_ctx::NO_GTID_MANY_TABLE_GROUPS; | ||
| 2438 | } | ||
| 2439 | } | ||
| 2440 | } | ||
| 2441 | |||
| 2442 | 156474 | return false; | |
| 2443 | } | ||
| 2444 | |||
| 2445 | /** | ||
| 2446 | Check if DROP TABLES or DROP DATABASE statement going to violate | ||
| 2447 | some foreign key constraint by dropping its parent table without | ||
| 2448 | dropping child at the same time. | ||
| 2449 | */ | ||
| 2450 | 155436 | static bool rm_table_check_fks(THD *thd, Drop_tables_ctx *drop_ctx) { | |
| 2451 | /* | ||
| 2452 | In FOREIGN_KEY_CHECKS=0 mode it is allowed to drop parent without | ||
| 2453 | dropping child at the same time, so we return early. | ||
| 2454 | In FOREIGN_KEY_CHECKS=1 mode we need to check if we are about to | ||
| 2455 | drop parent table without dropping child table. | ||
| 2456 | */ | ||
| 2457 |
2/2✓ Branch 0 taken 1363 times.
✓ Branch 1 taken 154073 times.
|
155436 | if (thd->variables.option_bits & OPTION_NO_FOREIGN_KEY_CHECKS) return false; |
| 2458 | |||
| 2459 | // Earlier we assert that only SEs supporting atomic DDL support FKs. | ||
| 2460 |
2/2✓ Branch 0 taken 95432 times.
✓ Branch 1 taken 154057 times.
|
249489 | for (TABLE_LIST *table : drop_ctx->base_atomic_tables) { |
| 2461 |
1/2✓ Branch 0 taken 95432 times.
✗ Branch 1 not taken.
|
95432 | dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client()); |
| 2462 | 95432 | const dd::Table *table_def = nullptr; | |
| 2463 |
4/8✓ Branch 0 taken 95432 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 95432 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 95432 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 95432 times.
|
95432 | if (thd->dd_client()->acquire(table->db, table->table_name, &table_def)) |
| 2464 | ✗ | return true; | |
| 2465 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 95432 times.
|
95432 | assert(table_def != nullptr); |
| 2466 | |||
| 2467 |
6/8✓ Branch 0 taken 95432 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 95432 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 95431 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 95431 times.
|
95432 | if (table_def && table_def->hidden() == dd::Abstract_table::HT_HIDDEN_SE) { |
| 2468 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_NO_SUCH_TABLE, MYF(0), table->db, table->table_name); |
| 2469 | assert(true); | ||
| 2470 | 1 | return true; | |
| 2471 | } | ||
| 2472 | |||
| 2473 |
3/4✓ Branch 0 taken 95431 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 342 times.
✓ Branch 3 taken 95416 times.
|
95758 | for (const dd::Foreign_key_parent *fk : table_def->foreign_key_parents()) { |
| 2474 |
2/2✓ Branch 0 taken 105 times.
✓ Branch 1 taken 237 times.
|
342 | if (drop_ctx->drop_database) { |
| 2475 | /* | ||
| 2476 | In case of DROP DATABASE list of tables to be dropped can be huge. | ||
| 2477 | We avoid scanning it by assuming that DROP DATABASE will drop all | ||
| 2478 | tables in the database and no tables from other databases. | ||
| 2479 | */ | ||
| 2480 |
1/2✓ Branch 0 taken 105 times.
✗ Branch 1 not taken.
|
105 | if (my_strcasecmp(table_alias_charset, fk->child_schema_name().c_str(), |
| 2481 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 101 times.
|
105 | table->db) != 0) { |
| 2482 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
8 | my_error(ER_FK_CANNOT_DROP_PARENT, MYF(0), table->table_name, |
| 2483 | 8 | fk->fk_name().c_str(), fk->child_table_name().c_str()); | |
| 2484 | 15 | return true; | |
| 2485 | } | ||
| 2486 | } else { | ||
| 2487 |
1/2✓ Branch 0 taken 237 times.
✗ Branch 1 not taken.
|
237 | if (my_strcasecmp(table_alias_charset, fk->child_schema_name().c_str(), |
| 2488 |
3/4✓ Branch 0 taken 237 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
✓ Branch 3 taken 217 times.
|
474 | table->db) == 0 && |
| 2489 |
3/4✓ Branch 0 taken 237 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
✓ Branch 3 taken 217 times.
|
237 | my_strcasecmp(table_alias_charset, fk->child_table_name().c_str(), |
| 2490 | table->table_name) == 0) | ||
| 2491 | 20 | continue; | |
| 2492 | |||
| 2493 | 217 | bool child_dropped = false; | |
| 2494 | |||
| 2495 |
4/6✓ Branch 0 taken 217 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 217 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 307 times.
✓ Branch 5 taken 11 times.
|
318 | for (TABLE_LIST *dropped : drop_ctx->base_atomic_tables) { |
| 2496 |
1/2✓ Branch 0 taken 307 times.
✗ Branch 1 not taken.
|
307 | if (my_strcasecmp(table_alias_charset, |
| 2497 | fk->child_schema_name().c_str(), | ||
| 2498 |
3/4✓ Branch 0 taken 307 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 206 times.
✓ Branch 3 taken 101 times.
|
614 | dropped->db) == 0 && |
| 2499 |
3/4✓ Branch 0 taken 307 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 206 times.
✓ Branch 3 taken 101 times.
|
307 | my_strcasecmp(table_alias_charset, fk->child_table_name().c_str(), |
| 2500 | dropped->table_name) == 0) { | ||
| 2501 | 206 | child_dropped = true; | |
| 2502 | 206 | break; | |
| 2503 | } | ||
| 2504 | } | ||
| 2505 | |||
| 2506 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 206 times.
|
217 | if (!child_dropped) { |
| 2507 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
22 | my_error(ER_FK_CANNOT_DROP_PARENT, MYF(0), table->table_name, |
| 2508 | 22 | fk->fk_name().c_str(), fk->child_table_name().c_str()); | |
| 2509 | 11 | return true; | |
| 2510 | } | ||
| 2511 | } | ||
| 2512 | } | ||
| 2513 |
2/2✓ Branch 0 taken 95416 times.
✓ Branch 1 taken 16 times.
|
95432 | } |
| 2514 | |||
| 2515 | 154057 | return false; | |
| 2516 | } | ||
| 2517 | |||
| 2518 | /** | ||
| 2519 | Update the unique constraint names for FKs which reference table | ||
| 2520 | being dropped. | ||
| 2521 | |||
| 2522 | @param thd Thread handle. | ||
| 2523 | @param parent_table_db Schema name for table being dropped. | ||
| 2524 | @param parent_table_name Name of the table being dropped. | ||
| 2525 | @param parent_table_def dd::Table object representing the dropped table. | ||
| 2526 | @param hton Handlerton for table's storage engine. | ||
| 2527 | |||
| 2528 | @retval operation outcome, false if no error. | ||
| 2529 | */ | ||
| 2530 | 133691 | static bool adjust_fk_children_for_parent_drop( | |
| 2531 | THD *thd, const char *parent_table_db, const char *parent_table_name, | ||
| 2532 | const dd::Table *parent_table_def, handlerton *hton [[maybe_unused]]) { | ||
| 2533 | 133691 | for (const dd::Foreign_key_parent *parent_fk : | |
| 2534 |
3/4✓ Branch 0 taken 133691 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 365 times.
✓ Branch 3 taken 133691 times.
|
267747 | parent_table_def->foreign_key_parents()) { |
| 2535 |
1/2✓ Branch 0 taken 365 times.
✗ Branch 1 not taken.
|
365 | if (my_strcasecmp(table_alias_charset, |
| 2536 | parent_fk->child_schema_name().c_str(), | ||
| 2537 |
3/4✓ Branch 0 taken 365 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29 times.
✓ Branch 3 taken 336 times.
|
730 | parent_table_db) == 0 && |
| 2538 |
3/4✓ Branch 0 taken 365 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 29 times.
✓ Branch 3 taken 336 times.
|
365 | my_strcasecmp(table_alias_charset, |
| 2539 | parent_fk->child_table_name().c_str(), | ||
| 2540 | parent_table_name) == 0) | ||
| 2541 | 274 | continue; | |
| 2542 | |||
| 2543 | 336 | dd::Table *child_table_def = nullptr; | |
| 2544 | |||
| 2545 |
4/8✓ Branch 0 taken 336 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 336 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 336 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 336 times.
|
1008 | if (thd->dd_client()->acquire_for_modification( |
| 2546 | 336 | parent_fk->child_schema_name().c_str(), | |
| 2547 | 336 | parent_fk->child_table_name().c_str(), &child_table_def)) | |
| 2548 | ✗ | return true; | |
| 2549 | |||
| 2550 |
2/2✓ Branch 0 taken 245 times.
✓ Branch 1 taken 91 times.
|
336 | if (child_table_def == nullptr) continue; |
| 2551 | |||
| 2552 |
6/10✓ Branch 0 taken 91 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 91 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 91 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 126 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 126 times.
✓ Branch 9 taken 91 times.
|
217 | for (dd::Foreign_key *fk : *(child_table_def->foreign_keys())) { |
| 2553 |
2/4✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 126 times.
✗ Branch 3 not taken.
|
126 | if (my_strcasecmp(table_alias_charset, |
| 2554 | fk->referenced_table_schema_name().c_str(), | ||
| 2555 |
3/4✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 91 times.
✓ Branch 3 taken 35 times.
|
252 | parent_table_db) == 0 && |
| 2556 |
4/6✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 126 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 91 times.
✓ Branch 5 taken 35 times.
|
126 | my_strcasecmp(table_alias_charset, |
| 2557 | fk->referenced_table_name().c_str(), | ||
| 2558 | parent_table_name) == 0) { | ||
| 2559 | // Note: Setting "" is interpreted as NULL. | ||
| 2560 |
2/4✓ Branch 0 taken 91 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 91 times.
✗ Branch 3 not taken.
|
91 | fk->set_unique_constraint_name(""); |
| 2561 | } | ||
| 2562 | } | ||
| 2563 | |||
| 2564 |
2/4✓ Branch 0 taken 91 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 91 times.
|
91 | if (thd->dd_client()->update(child_table_def)) return true; |
| 2565 | |||
| 2566 | char buff_db[NAME_LEN + 1]; | ||
| 2567 | char buff_table[NAME_LEN + 1]; | ||
| 2568 | |||
| 2569 | 91 | my_stpncpy(buff_db, parent_fk->child_schema_name().c_str(), NAME_LEN); | |
| 2570 | 91 | my_stpncpy(buff_table, parent_fk->child_table_name().c_str(), NAME_LEN); | |
| 2571 | |||
| 2572 | /* | ||
| 2573 | In lower-case-table-names == 2 mode we store original versions of | ||
| 2574 | table and db names in the data-dictionary. Hence they need to be | ||
| 2575 | lowercased to be used with Table and Table Definition Caches. | ||
| 2576 | */ | ||
| 2577 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 91 times.
|
91 | if (lower_case_table_names == 2) { |
| 2578 | ✗ | my_casedn_str(system_charset_info, buff_db); | |
| 2579 | ✗ | my_casedn_str(system_charset_info, buff_table); | |
| 2580 | } | ||
| 2581 | |||
| 2582 |
1/2✓ Branch 0 taken 91 times.
✗ Branch 1 not taken.
|
91 | mysql_ha_flush_table(thd, buff_db, buff_table); |
| 2583 |
1/2✓ Branch 0 taken 91 times.
✗ Branch 1 not taken.
|
91 | close_all_tables_for_name(thd, buff_db, buff_table, false); |
| 2584 | |||
| 2585 | #ifdef DISABLED_UNTIL_WL9533 | ||
| 2586 | /* | ||
| 2587 | TODO: Simply removing entries from InnoDB internal cache breaks | ||
| 2588 | its FK checking logic at the moment. This is to be solved | ||
| 2589 | as part of WL#9533. We might have to replace invalidation | ||
| 2590 | with cache update to do this.Also we might have to postpone | ||
| 2591 | such invalidation/update until statement commit time. | ||
| 2592 | */ | ||
| 2593 | if (hton->dict_cache_reset) | ||
| 2594 | hton->dict_cache_reset(parent_fk->child_schema_name().c_str(), | ||
| 2595 | parent_fk->child_table_name().c_str()); | ||
| 2596 | #endif | ||
| 2597 | } | ||
| 2598 | |||
| 2599 | 133691 | return false; | |
| 2600 | } | ||
| 2601 | |||
| 2602 | /** | ||
| 2603 | * Validates the ALTER TABLE command with respect to any secondary engine | ||
| 2604 | * operations. | ||
| 2605 | * | ||
| 2606 | * @param alter_info Alter table operations. | ||
| 2607 | * @param create_info Table option changes. | ||
| 2608 | * @param table The table that is being altered. | ||
| 2609 | * | ||
| 2610 | * @return True if invalid, false otherwise. | ||
| 2611 | */ | ||
| 2612 | 91860 | static bool validate_secondary_engine_option(const Alter_info &alter_info, | |
| 2613 | const HA_CREATE_INFO &create_info, | ||
| 2614 | const TABLE &table) { | ||
| 2615 | // Validation necessary only for tables with a secondary engine defined. | ||
| 2616 |
2/2✓ Branch 0 taken 91822 times.
✓ Branch 1 taken 38 times.
|
91860 | if (!table.s->has_secondary_engine()) return false; |
| 2617 | |||
| 2618 | // Changing table option is the only valid ALTER TABLE operation. | ||
| 2619 | 38 | constexpr uint64_t supported_alter_operations = Alter_info::ALTER_OPTIONS; | |
| 2620 | |||
| 2621 | // The only table option that may be changed is SECONDARY_ENGINE. | ||
| 2622 | 38 | constexpr uint64_t supported_table_options = HA_CREATE_USED_SECONDARY_ENGINE; | |
| 2623 | |||
| 2624 |
2/2✓ Branch 0 taken 33 times.
✓ Branch 1 taken 5 times.
|
38 | if (alter_info.flags & ~supported_alter_operations || |
| 2625 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 29 times.
|
33 | create_info.used_fields & ~supported_table_options) { |
| 2626 | 9 | my_error(ER_SECONDARY_ENGINE_DDL, MYF(0)); | |
| 2627 | 9 | return true; | |
| 2628 | } | ||
| 2629 | |||
| 2630 | // Secondary engine of a table must be set to NULL before it can be redefined. | ||
| 2631 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 28 times.
|
29 | if (create_info.secondary_engine.str != nullptr) { |
| 2632 | 1 | my_error(ER_SECONDARY_ENGINE, MYF(0), | |
| 2633 | "Table already has a secondary engine defined"); | ||
| 2634 | 1 | return true; | |
| 2635 | } | ||
| 2636 | |||
| 2637 | 28 | return false; | |
| 2638 | } | ||
| 2639 | |||
| 2640 | /** | ||
| 2641 | * Loads a table from its primary engine into its secondary engine. | ||
| 2642 | * | ||
| 2643 | * This call assumes that MDL_SHARED_NO_WRITE/SECLOAD_SCAN_START_MDL lock | ||
| 2644 | * on the table have been acquired by caller. During its execution it may | ||
| 2645 | * downgrade this lock to MDL_SHARED_UPGRADEABLE/SECLOAD_PAR_SCAN_MDL. | ||
| 2646 | * | ||
| 2647 | * @param thd Thread handler. | ||
| 2648 | * @param table Table in primary storage engine. | ||
| 2649 | * | ||
| 2650 | * @return True if error, false otherwise. | ||
| 2651 | */ | ||
| 2652 | 91 | static bool secondary_engine_load_table(THD *thd, const TABLE &table) { | |
| 2653 |
2/4✓ Branch 0 taken 91 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 91 times.
|
91 | assert(thd->mdl_context.owns_equal_or_stronger_lock( |
| 2654 | MDL_key::TABLE, table.s->db.str, table.s->table_name.str, | ||
| 2655 | SECLOAD_SCAN_START_MDL)); | ||
| 2656 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 91 times.
|
91 | assert(table.s->has_secondary_engine()); |
| 2657 | |||
| 2658 | // At least one column must be loaded into the secondary engine. | ||
| 2659 |
3/4✓ Branch 0 taken 91 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 89 times.
|
91 | if (bitmap_bits_set(table.read_set) == 0) { |
| 2660 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | my_error(ER_SECONDARY_ENGINE, MYF(0), |
| 2661 | "All columns marked as NOT SECONDARY"); | ||
| 2662 | 2 | return true; | |
| 2663 | } | ||
| 2664 | |||
| 2665 | // The defined secondary engine must be the name of a valid storage engine. | ||
| 2666 | plugin_ref plugin = | ||
| 2667 |
1/2✓ Branch 0 taken 89 times.
✗ Branch 1 not taken.
|
89 | ha_resolve_by_name(thd, &table.s->secondary_engine, false); |
| 2668 |
6/8✓ Branch 0 taken 88 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 88 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 88 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 88 times.
|
89 | if ((plugin == nullptr) || !plugin_is_ready(table.s->secondary_engine, |
| 2669 | MYSQL_STORAGE_ENGINE_PLUGIN)) { | ||
| 2670 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), table.s->secondary_engine.str); |
| 2671 | 1 | return true; | |
| 2672 | } | ||
| 2673 | |||
| 2674 | // The engine must support being used as a secondary engine. | ||
| 2675 | 88 | handlerton *hton = plugin_data<handlerton *>(plugin); | |
| 2676 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 87 times.
|
88 | if (!(hton->flags & HTON_IS_SECONDARY_ENGINE)) { |
| 2677 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_SECONDARY_ENGINE, MYF(0), |
| 2678 | "Unsupported secondary storage engine"); | ||
| 2679 | 1 | return true; | |
| 2680 | } | ||
| 2681 | |||
| 2682 | // Get handler to the secondary engine into which the table will be loaded. | ||
| 2683 | 87 | const bool is_partitioned = table.s->m_part_info != nullptr; | |
| 2684 | unique_ptr_destroy_only<handler> handler( | ||
| 2685 |
1/2✓ Branch 0 taken 87 times.
✗ Branch 1 not taken.
|
87 | get_new_handler(table.s, is_partitioned, thd->mem_root, hton)); |
| 2686 | |||
| 2687 | // Load table from primary into secondary engine and add to change | ||
| 2688 | // propagation if that is enabled. | ||
| 2689 |
1/2✓ Branch 0 taken 87 times.
✗ Branch 1 not taken.
|
87 | return handler->ha_load_table(table); |
| 2690 | 87 | } | |
| 2691 | |||
| 2692 | /** | ||
| 2693 | * Unloads a table from its secondary engine. | ||
| 2694 | * | ||
| 2695 | * @note An MDL_EXCLUSIVE or stronger lock on the table must have been acquired | ||
| 2696 | * prior to calling this function to ensure that queries already offloaded to | ||
| 2697 | * the secondary engine finished execution before unloading the table. | ||
| 2698 | * | ||
| 2699 | * @param thd Thread handler. | ||
| 2700 | * @param db_name Database name. | ||
| 2701 | * @param table_name Table name. | ||
| 2702 | * @param table_def Table definition. | ||
| 2703 | * @param error_if_not_loaded If true and the table is not loaded in the | ||
| 2704 | * secondary engine, this function will return an | ||
| 2705 | * error. If false, this function will not return an | ||
| 2706 | * error if the table is not loaded in the secondary | ||
| 2707 | * engine. | ||
| 2708 | * | ||
| 2709 | * @return True if error, false otherwise. | ||
| 2710 | */ | ||
| 2711 | 133772 | static bool secondary_engine_unload_table(THD *thd, const char *db_name, | |
| 2712 | const char *table_name, | ||
| 2713 | const dd::Table &table_def, | ||
| 2714 | bool error_if_not_loaded) { | ||
| 2715 |
2/4✓ Branch 0 taken 133772 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 133772 times.
|
133772 | assert(thd->mdl_context.owns_equal_or_stronger_lock( |
| 2716 | MDL_key::TABLE, db_name, table_name, MDL_EXCLUSIVE)); | ||
| 2717 | |||
| 2718 | // Nothing to unload if table has no secondary engine defined. | ||
| 2719 | LEX_CSTRING secondary_engine; | ||
| 2720 |
7/12✓ Branch 0 taken 133772 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 133772 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 133772 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 150 times.
✓ Branch 7 taken 133622 times.
✓ Branch 8 taken 133622 times.
✓ Branch 9 taken 150 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
267694 | if (!table_def.options().exists("secondary_engine") || |
| 2721 |
7/14✓ Branch 0 taken 150 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 150 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 150 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 150 times.
✓ Branch 8 taken 150 times.
✓ Branch 9 taken 133622 times.
✓ Branch 10 taken 133772 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
|
133922 | table_def.options().get("secondary_engine", &secondary_engine, |
| 2722 | thd->mem_root)) | ||
| 2723 | 133622 | return false; | |
| 2724 | |||
| 2725 | // Get handlerton of secondary engine. It may happen that no handlerton is | ||
| 2726 | // found either if the defined secondary engine is invalid (if so, the table | ||
| 2727 | // was never loaded either) or if the secondary engine has been uninstalled | ||
| 2728 | // after tables were loaded into it (in which case the tables have already | ||
| 2729 | // been unloaded). | ||
| 2730 |
1/2✓ Branch 0 taken 150 times.
✗ Branch 1 not taken.
|
150 | plugin_ref plugin = ha_resolve_by_name(thd, &secondary_engine, false); |
| 2731 |
4/4✓ Branch 0 taken 117 times.
✓ Branch 1 taken 33 times.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 117 times.
|
267 | if ((plugin == nullptr) || |
| 2732 |
2/4✓ Branch 0 taken 117 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 117 times.
|
117 | !plugin_is_ready(secondary_engine, MYSQL_STORAGE_ENGINE_PLUGIN)) { |
| 2733 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
|
33 | if (error_if_not_loaded) |
| 2734 | ✗ | my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), secondary_engine); | |
| 2735 | 33 | return error_if_not_loaded; | |
| 2736 | } | ||
| 2737 | 117 | handlerton *hton = plugin_data<handlerton *>(plugin); | |
| 2738 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 117 times.
|
117 | if (hton == nullptr) { |
| 2739 | ✗ | if (error_if_not_loaded) | |
| 2740 | ✗ | my_error(ER_SECONDARY_ENGINE, MYF(0), | |
| 2741 | "Table is not loaded on a secondary engine"); | ||
| 2742 | ✗ | return error_if_not_loaded; | |
| 2743 | } | ||
| 2744 | |||
| 2745 | // The defined secondary engine is a valid storage engine. However, if the | ||
| 2746 | // engine is not a valid secondary engine, no tables have been loaded and | ||
| 2747 | // there is nothing to be done. | ||
| 2748 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 112 times.
|
117 | if (!(hton->flags & HTON_IS_SECONDARY_ENGINE)) return false; |
| 2749 | |||
| 2750 | // Get handler for table in secondary engine. | ||
| 2751 |
1/2✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
|
112 | const bool is_partitioned = table_def.partition_type() != dd::Table::PT_NONE; |
| 2752 | unique_ptr_destroy_only<handler> handler( | ||
| 2753 |
1/2✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
|
112 | get_new_handler(nullptr, is_partitioned, thd->mem_root, hton)); |
| 2754 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
|
112 | if (handler == nullptr) return true; |
| 2755 | |||
| 2756 | // Unload table from secondary engine. | ||
| 2757 |
1/2✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
|
112 | return handler->ha_unload_table(db_name, table_name, error_if_not_loaded) > 0; |
| 2758 | 112 | } | |
| 2759 | |||
| 2760 | /** | ||
| 2761 | Auxiliary function which drops single base table. | ||
| 2762 | |||
| 2763 | @param thd Thread handler. | ||
| 2764 | @param drop_ctx DROP TABLES runtime context. | ||
| 2765 | @param table Table to drop. | ||
| 2766 | @param atomic Indicates whether table to be dropped is in SE | ||
| 2767 | which supports atomic DDL, so changes to the | ||
| 2768 | data-dictionary should not be committed. | ||
| 2769 | @param[in,out] post_ddl_htons Set of handlertons for tables in SEs supporting | ||
| 2770 | atomic DDL for which post-DDL hook needs to | ||
| 2771 | be called after statement commit or rollback. | ||
| 2772 | @param[in,out] fk_invalidator Object keeping track of which dd::Table | ||
| 2773 | objects need to be invalidated since the | ||
| 2774 | correspond to the parent tables for FKs | ||
| 2775 | on a table being dropped. | ||
| 2776 | @param[in,out] safe_to_release_mdl Under LOCK TABLES set of metadata locks | ||
| 2777 | on tables dropped which is safe to | ||
| 2778 | release after DROP operation. | ||
| 2779 | @param foreach_table_root MEM_ROOT which can be used for allocating | ||
| 2780 | objects which lifetime is limited to dropping | ||
| 2781 | of single table. | ||
| 2782 | |||
| 2783 | @sa mysql_rm_table_no_locks(). | ||
| 2784 | |||
| 2785 | @retval False - ok | ||
| 2786 | @retval True - error | ||
| 2787 | */ | ||
| 2788 | |||
| 2789 | 133711 | static bool drop_base_table(THD *thd, const Drop_tables_ctx &drop_ctx, | |
| 2790 | TABLE_LIST *table, bool atomic, | ||
| 2791 | std::set<handlerton *> *post_ddl_htons, | ||
| 2792 | Foreign_key_parents_invalidator *fk_invalidator, | ||
| 2793 | std::vector<MDL_ticket *> *safe_to_release_mdl, | ||
| 2794 | MEM_ROOT *foreach_table_root) { | ||
| 2795 | char path[FN_REFLEN + 1]; | ||
| 2796 | |||
| 2797 | /* Check that we have an exclusive lock on the table to be dropped. */ | ||
| 2798 |
2/4✓ Branch 0 taken 133711 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 133711 times.
|
133711 | assert(thd->mdl_context.owns_equal_or_stronger_lock( |
| 2799 | MDL_key::TABLE, table->db, table->table_name, MDL_EXCLUSIVE)); | ||
| 2800 | |||
| 2801 | /* | ||
| 2802 | Good point to check if we were killed for non-atomic tables group. | ||
| 2803 | All previous tables are dropped both in SE and data-dictionary and | ||
| 2804 | corresponding DROP TABLE statements are written to binary log. | ||
| 2805 | We didn't do anything for the current table yet. | ||
| 2806 | |||
| 2807 | For atomic tables the exact place of this check should not matter. | ||
| 2808 | */ | ||
| 2809 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 133711 times.
|
133711 | if (thd->killed) return true; |
| 2810 | |||
| 2811 | 133711 | const dd::Table *table_def = nullptr; | |
| 2812 |
4/8✓ Branch 0 taken 133711 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 133711 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 133711 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 133711 times.
|
133711 | if (thd->dd_client()->acquire(table->db, table->table_name, &table_def)) |
| 2813 | ✗ | return true; | |
| 2814 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 133711 times.
|
133711 | assert(table_def != nullptr); |
| 2815 | |||
| 2816 |
4/8✓ Branch 0 taken 133711 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 133711 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 133711 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 133711 times.
|
133711 | if (table_def && table_def->hidden() == dd::Abstract_table::HT_HIDDEN_SE) { |
| 2817 | ✗ | my_error(ER_NO_SUCH_TABLE, MYF(0), table->db, table->table_name); | |
| 2818 | assert(true); | ||
| 2819 | ✗ | return true; | |
| 2820 | } | ||
| 2821 | |||
| 2822 | // Drop table from secondary engine. | ||
| 2823 |
2/4✓ Branch 0 taken 133711 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 133711 times.
|
133711 | if (secondary_engine_unload_table(thd, table->db, table->table_name, |
| 2824 | *table_def, false)) | ||
| 2825 | ✗ | return true; /* purecov: inspected */ | |
| 2826 | |||
| 2827 | 133711 | handlerton *hton{nullptr}; | |
| 2828 |
2/4✓ Branch 0 taken 133711 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 133711 times.
|
133711 | if (dd::table_storage_engine(thd, table_def, &hton)) { |
| 2829 | ✗ | assert(false); | |
| 2830 | return true; | ||
| 2831 | } | ||
| 2832 | |||
| 2833 | 133711 | histograms::results_map results; | |
| 2834 | bool histogram_error = | ||
| 2835 |
1/2✓ Branch 0 taken 133711 times.
✗ Branch 1 not taken.
|
133711 | histograms::drop_all_histograms(thd, *table, *table_def, results); |
| 2836 | |||
| 2837 |
4/6✓ Branch 0 taken 133711 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 133710 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
133711 | DBUG_EXECUTE_IF("fail_after_drop_histograms", { |
| 2838 | my_error(ER_UNABLE_TO_DROP_COLUMN_STATISTICS, MYF(0), "dummy_column", | ||
| 2839 | table->db, table->table_name); | ||
| 2840 | histogram_error = true; | ||
| 2841 | }); | ||
| 2842 | |||
| 2843 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 133710 times.
|
133711 | if (histogram_error) { |
| 2844 | /* | ||
| 2845 | Do a rollback request, so that we avoid commit from being called at a | ||
| 2846 | later stage. | ||
| 2847 | */ | ||
| 2848 | 1 | thd->transaction_rollback_request = true; | |
| 2849 | 1 | return true; | |
| 2850 | } | ||
| 2851 | |||
| 2852 |
2/2✓ Branch 0 taken 63 times.
✓ Branch 1 taken 133647 times.
|
133710 | if (thd->locked_tables_mode) { |
| 2853 | /* | ||
| 2854 | Under LOCK TABLES we still have table open at this point. | ||
| 2855 | Close it and remove all instances from Table/Table Definition | ||
| 2856 | cache. | ||
| 2857 | |||
| 2858 | Note that we won't try to reopen tables in storage engines | ||
| 2859 | supporting atomic DDL those removal will be later rolled back | ||
| 2860 | thanks to some error. Such situations should be fairly rare. | ||
| 2861 | */ | ||
| 2862 |
1/2✓ Branch 0 taken 63 times.
✗ Branch 1 not taken.
|
63 | close_all_tables_for_name(thd, table->db, table->table_name, true); |
| 2863 | |||
| 2864 | /* | ||
| 2865 | Find out if it is going to be safe to release MDL after dropping | ||
| 2866 | table under LOCK TABLES. It is not if we are dropping parent and | ||
| 2867 | leave child table around and locked. | ||
| 2868 | */ | ||
| 2869 | 63 | bool safe_to_release = true; | |
| 2870 | |||
| 2871 |
2/4✓ Branch 0 taken 63 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 63 times.
|
63 | if (!table_def->foreign_key_parents().empty()) { |
| 2872 | // We don't have SEs which support FKs and not atomic DDL at the moment. | ||
| 2873 | ✗ | assert(atomic); | |
| 2874 | |||
| 2875 | ✗ | for (const dd::Foreign_key_parent *fk : | |
| 2876 | ✗ | table_def->foreign_key_parents()) { | |
| 2877 | ✗ | if (my_strcasecmp(table_alias_charset, fk->child_schema_name().c_str(), | |
| 2878 | ✗ | table->db) == 0 && | |
| 2879 | ✗ | my_strcasecmp(table_alias_charset, fk->child_table_name().c_str(), | |
| 2880 | table->table_name) == 0) | ||
| 2881 | ✗ | continue; | |
| 2882 | |||
| 2883 | ✗ | bool child_dropped = false; | |
| 2884 | |||
| 2885 | ✗ | for (TABLE_LIST *dropped : drop_ctx.base_atomic_tables) { | |
| 2886 | ✗ | if (my_strcasecmp(table_alias_charset, | |
| 2887 | fk->child_schema_name().c_str(), | ||
| 2888 | ✗ | dropped->db) == 0 && | |
| 2889 | ✗ | my_strcasecmp(table_alias_charset, fk->child_table_name().c_str(), | |
| 2890 | dropped->table_name) == 0) { | ||
| 2891 | ✗ | child_dropped = true; | |
| 2892 | ✗ | break; | |
| 2893 | } | ||
| 2894 | } | ||
| 2895 | |||
| 2896 | ✗ | if (!child_dropped) { | |
| 2897 | char buff_db[NAME_LEN + 1]; | ||
| 2898 | char buff_table[NAME_LEN + 1]; | ||
| 2899 | |||
| 2900 | ✗ | my_stpncpy(buff_db, fk->child_schema_name().c_str(), NAME_LEN); | |
| 2901 | ✗ | my_stpncpy(buff_table, fk->child_table_name().c_str(), NAME_LEN); | |
| 2902 | |||
| 2903 | /* | ||
| 2904 | In lower-case-table-names == 2 mode we store original versions of | ||
| 2905 | table and db names in the data-dictionary. Hence they need to be | ||
| 2906 | lowercased to produce correct MDL key. | ||
| 2907 | */ | ||
| 2908 | ✗ | if (lower_case_table_names == 2) { | |
| 2909 | /* purecov: begin inspected */ | ||
| 2910 | ✗ | my_casedn_str(system_charset_info, buff_db); | |
| 2911 | ✗ | my_casedn_str(system_charset_info, buff_table); | |
| 2912 | /* purecov: end */ | ||
| 2913 | } | ||
| 2914 | |||
| 2915 | ✗ | if (thd->mdl_context.owns_equal_or_stronger_lock( | |
| 2916 | MDL_key::TABLE, buff_db, buff_table, | ||
| 2917 | MDL_SHARED_NO_READ_WRITE)) { | ||
| 2918 | /* | ||
| 2919 | Child is not going to be dropped and locked in mode which | ||
| 2920 | requires foreign key checks. It is not safe to release MDL. | ||
| 2921 | */ | ||
| 2922 | ✗ | safe_to_release = false; | |
| 2923 | ✗ | break; | |
| 2924 | } | ||
| 2925 | } | ||
| 2926 | } | ||
| 2927 | } | ||
| 2928 | |||
| 2929 |
1/2✓ Branch 0 taken 63 times.
✗ Branch 1 not taken.
|
63 | if (safe_to_release) |
| 2930 |
1/2✓ Branch 0 taken 63 times.
✗ Branch 1 not taken.
|
63 | safe_to_release_mdl->push_back(table->mdl_request.ticket); |
| 2931 | } else { | ||
| 2932 |
1/2✓ Branch 0 taken 133647 times.
✗ Branch 1 not taken.
|
133647 | tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db, table->table_name, |
| 2933 | false); | ||
| 2934 | } | ||
| 2935 | |||
| 2936 | /* | ||
| 2937 | If the table being dropped is a internal temporary table that was | ||
| 2938 | created by ALTER TABLE, we need to mark it as internal tmp table. | ||
| 2939 | This will enable us to build the filename as we build during ALTER | ||
| 2940 | TABLE. | ||
| 2941 | */ | ||
| 2942 |
3/4✓ Branch 0 taken 133710 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 133708 times.
|
133710 | if (table_def->hidden() == dd::Abstract_table::HT_HIDDEN_DDL) |
| 2943 | 2 | table->internal_tmp_table = true; | |
| 2944 | |||
| 2945 |
1/2✓ Branch 0 taken 133710 times.
✗ Branch 1 not taken.
|
133710 | (void)build_table_filename(path, sizeof(path) - 1, table->db, |
| 2946 | table->table_name, "", | ||
| 2947 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 133708 times.
|
133710 | table->internal_tmp_table ? FN_IS_TMP : 0); |
| 2948 | |||
| 2949 | /* | ||
| 2950 | Use memory root that is freed right after table processing for allocating | ||
| 2951 | dummy handler object for calling handler::delete_table() in order to avoid | ||
| 2952 | gobbling up memory when lots of tables are deleted. | ||
| 2953 | */ | ||
| 2954 | 133710 | MEM_ROOT *save_thd_mem_root = thd->mem_root; | |
| 2955 | 133710 | thd->mem_root = foreach_table_root; | |
| 2956 | |||
| 2957 | 267419 | int error = ha_delete_table(thd, hton, path, table->db, table->table_name, | |
| 2958 |
1/2✓ Branch 0 taken 133709 times.
✗ Branch 1 not taken.
|
133710 | table_def, !drop_ctx.drop_database); |
| 2959 | |||
| 2960 | 133709 | thd->mem_root = save_thd_mem_root; | |
| 2961 | |||
| 2962 | /* | ||
| 2963 | Table was present in data-dictionary but is missing in storage engine. | ||
| 2964 | This situation can occur for SEs which don't support atomic DDL due | ||
| 2965 | to crashes. In this case we allow table removal from data-dictionary | ||
| 2966 | and reporting success if IF EXISTS clause was specified. | ||
| 2967 | |||
| 2968 | Such situation should not be possible for SEs supporting atomic DDL, | ||
| 2969 | but we still play safe even in this case and allow table removal. | ||
| 2970 | */ | ||
| 2971 |
4/6✓ Branch 0 taken 96428 times.
✓ Branch 1 taken 37281 times.
✓ Branch 2 taken 96428 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 96428 times.
✗ Branch 5 not taken.
|
133709 | assert(!atomic || (error != ENOENT && error != HA_ERR_NO_SUCH_TABLE)); |
| 2972 | |||
| 2973 |
4/4✓ Branch 0 taken 133697 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 133685 times.
|
133709 | if ((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE) && |
| 2974 |
2/2✓ Branch 0 taken 19 times.
✓ Branch 1 taken 5 times.
|
24 | drop_ctx.if_exists) { |
| 2975 | 19 | error = 0; | |
| 2976 |
1/2✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
|
19 | thd->clear_error(); |
| 2977 | } | ||
| 2978 | |||
| 2979 |
4/6✓ Branch 0 taken 96428 times.
✓ Branch 1 taken 37281 times.
✓ Branch 2 taken 96428 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 96428 times.
✗ Branch 5 not taken.
|
133709 | if (atomic && hton->post_ddl) post_ddl_htons->insert(hton); |
| 2980 | |||
| 2981 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 133691 times.
|
133709 | if (error) { |
| 2982 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | if (error == HA_ERR_ROW_IS_REFERENCED) |
| 2983 | ✗ | my_error(ER_ROW_IS_REFERENCED, MYF(0)); | |
| 2984 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | else if (error == HA_ERR_TOO_MANY_CONCURRENT_TRXS) |
| 2985 | ✗ | my_error(HA_ERR_TOO_MANY_CONCURRENT_TRXS, MYF(0)); | |
| 2986 | else { | ||
| 2987 | 18 | String tbl_name; | |
| 2988 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | append_table_name(&tbl_name, table); |
| 2989 |
6/8✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 13 times.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
|
18 | my_error(((error == ENOENT || error == HA_ERR_NO_SUCH_TABLE) |
| 2990 | ? ER_ENGINE_CANT_DROP_MISSING_TABLE | ||
| 2991 | : ER_ENGINE_CANT_DROP_TABLE), | ||
| 2992 | MYF(0), tbl_name.c_ptr()); | ||
| 2993 | 18 | } | |
| 2994 | 18 | return true; | |
| 2995 | } | ||
| 2996 | |||
| 2997 | #ifdef HAVE_PSI_SP_INTERFACE | ||
| 2998 |
1/2✓ Branch 0 taken 133691 times.
✗ Branch 1 not taken.
|
133691 | remove_all_triggers_from_perfschema(table->db, *table_def); |
| 2999 | #endif | ||
| 3000 | /* | ||
| 3001 | Remove table from data-dictionary and immediately commit this change | ||
| 3002 | if we are removing table in SE which does not support atomic DDL. | ||
| 3003 | This way chances of SE and data-dictionary getting out of sync in | ||
| 3004 | case of crash are reduced. | ||
| 3005 | |||
| 3006 | Things will go bad if we will fail to delete table from data-dictionary | ||
| 3007 | as table is already gone in SE. But this should be really rare situation | ||
| 3008 | (OOM, out of disk space, bugs). Also user can fix it by running DROP TABLE | ||
| 3009 | IF EXISTS on the same table again. | ||
| 3010 | |||
| 3011 | Don't commit the changes if table belongs to SE supporting atomic DDL. | ||
| 3012 | */ | ||
| 3013 | |||
| 3014 |
1/2✓ Branch 0 taken 133691 times.
✗ Branch 1 not taken.
|
133691 | if (adjust_fk_children_for_parent_drop(thd, table->db, table->table_name, |
| 3015 |
2/4✓ Branch 0 taken 133691 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 133691 times.
|
267382 | table_def, hton) || |
| 3016 |
2/4✓ Branch 0 taken 133691 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 133691 times.
|
133691 | adjust_fk_parents(thd, table->db, table->table_name, false, nullptr)) |
| 3017 | ✗ | return true; | |
| 3018 | |||
| 3019 |
6/10✓ Branch 0 taken 133691 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 133691 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 133691 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1026 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1026 times.
✓ Branch 9 taken 133691 times.
|
134717 | for (const dd::Foreign_key *fk : table_def->foreign_keys()) { |
| 3020 |
2/4✓ Branch 0 taken 1026 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1026 times.
✗ Branch 3 not taken.
|
1026 | if (my_strcasecmp(table_alias_charset, |
| 3021 | fk->referenced_table_schema_name().c_str(), | ||
| 3022 |
4/4✓ Branch 0 taken 1011 times.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 29 times.
✓ Branch 3 taken 997 times.
|
2037 | table->db) == 0 && |
| 3023 |
4/6✓ Branch 0 taken 1011 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1011 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 29 times.
✓ Branch 5 taken 982 times.
|
1011 | my_strcasecmp(table_alias_charset, fk->referenced_table_name().c_str(), |
| 3024 | table->table_name) == 0) | ||
| 3025 | 29 | continue; | |
| 3026 | |||
| 3027 | char buff_db[NAME_LEN + 1]; | ||
| 3028 | char buff_table[NAME_LEN + 1]; | ||
| 3029 |
1/2✓ Branch 0 taken 997 times.
✗ Branch 1 not taken.
|
997 | my_stpncpy(buff_db, fk->referenced_table_schema_name().c_str(), NAME_LEN); |
| 3030 |
1/2✓ Branch 0 taken 997 times.
✗ Branch 1 not taken.
|
997 | my_stpncpy(buff_table, fk->referenced_table_name().c_str(), NAME_LEN); |
| 3031 | |||
| 3032 | /* | ||
| 3033 | In lower-case-table-names == 2 mode we store original versions of table | ||
| 3034 | and db names in the data-dictionary. Hence they need to be lowercased | ||
| 3035 | before being used for TDC invalidation. | ||
| 3036 | */ | ||
| 3037 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 997 times.
|
997 | if (lower_case_table_names == 2) { |
| 3038 | ✗ | my_casedn_str(system_charset_info, buff_db); | |
| 3039 | ✗ | my_casedn_str(system_charset_info, buff_table); | |
| 3040 | } | ||
| 3041 | |||
| 3042 | // We don't have any SEs which support FKs but do not support atomic DDL. | ||
| 3043 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 997 times.
|
997 | assert(atomic); |
| 3044 | |||
| 3045 |
1/2✓ Branch 0 taken 997 times.
✗ Branch 1 not taken.
|
997 | fk_invalidator->add(buff_db, buff_table, hton); |
| 3046 | } | ||
| 3047 | |||
| 3048 | 133691 | dd::Schema_MDL_locker mdl_locker(thd); | |
| 3049 |
2/4✓ Branch 0 taken 133691 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 133691 times.
|
133691 | if (mdl_locker.ensure_locked(table->db)) return true; |
| 3050 |
1/2✓ Branch 0 taken 133691 times.
✗ Branch 1 not taken.
|
133691 | bool result = dd::drop_table(thd, table->db, table->table_name, *table_def); |
| 3051 | |||
| 3052 |
3/4✓ Branch 0 taken 37276 times.
✓ Branch 1 taken 96415 times.
✓ Branch 2 taken 37276 times.
✗ Branch 3 not taken.
|
133691 | if (!atomic) result = trans_intermediate_ddl_commit(thd, result); |
| 3053 | |||
| 3054 | /* | ||
| 3055 | In DROP DATABASE we can safely skip updating dependent views belonging | ||
| 3056 | to the same database if we know that they will be dropped atomically | ||
| 3057 | with our table. | ||
| 3058 | */ | ||
| 3059 |
1/2✓ Branch 0 taken 133691 times.
✗ Branch 1 not taken.
|
133691 | result |= mark_referencing_views_invalid(thd, table, |
| 3060 |
2/2✓ Branch 0 taken 9052 times.
✓ Branch 1 taken 1179 times.
|
133691 | (drop_ctx.drop_database && atomic), |
| 3061 |
2/2✓ Branch 0 taken 10231 times.
✓ Branch 1 taken 123460 times.
|
133691 | !atomic, foreach_table_root); |
| 3062 | |||
| 3063 | 133691 | return result; | |
| 3064 | 133710 | } | |
| 3065 | |||
| 3066 | /** | ||
| 3067 | Execute the drop of a normal or temporary table. | ||
| 3068 | |||
| 3069 | @param thd Thread handler | ||
| 3070 | @param tables Tables to drop | ||
| 3071 | @param if_exists If set, don't give an error if table doesn't exists. | ||
| 3072 | In this case we give an warning of level 'NOTE' | ||
| 3073 | @param drop_temporary Only drop temporary tables | ||
| 3074 | @param drop_database This is DROP DATABASE statement. Drop views | ||
| 3075 | and handle binary logging in a special way. | ||
| 3076 | @param[out] dropped_non_atomic_flag Indicates whether we have dropped some | ||
| 3077 | tables in SEs which don't support atomic | ||
| 3078 | DDL. | ||
| 3079 | @param[out] post_ddl_htons Set of handlertons for tables in SEs supporting | ||
| 3080 | atomic DDL for which post-DDL hook needs to | ||
| 3081 | be called after statement commit or rollback. | ||
| 3082 | @param[out] fk_invalidator Set of parent tables which participate in FKs | ||
| 3083 | together with tables dropped and which entries | ||
| 3084 | in DD cache need to be invalidated as result | ||
| 3085 | of DROP operation. | ||
| 3086 | @param[out] safe_to_release_mdl Under LOCK TABLES set of metadata locks on | ||
| 3087 | tables dropped which is safe to release | ||
| 3088 | after DROP operation. | ||
| 3089 | |||
| 3090 | @retval False - ok | ||
| 3091 | @retval True - error | ||
| 3092 | |||
| 3093 | @note This function assumes that metadata locks have already been taken. | ||
| 3094 | It is also assumed that the tables have been removed from TDC. | ||
| 3095 | |||
| 3096 | @note This function assumes that temporary tables to be dropped have | ||
| 3097 | been pre-opened using corresponding table list elements. | ||
| 3098 | |||
| 3099 | @todo When logging to the binary log, we should log | ||
| 3100 | tmp_tables and transactional tables as separate statements if we | ||
| 3101 | are in a transaction; This is needed to get these tables into the | ||
| 3102 | cached binary log that is only written on COMMIT. | ||
| 3103 | The current code only writes DROP statements that only uses temporary | ||
| 3104 | tables to the cache binary log. This should be ok on most cases, but | ||
| 3105 | not all. | ||
| 3106 | */ | ||
| 3107 | |||
| 3108 | 156486 | bool mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, | |
| 3109 | bool drop_temporary, bool drop_database, | ||
| 3110 | bool *dropped_non_atomic_flag, | ||
| 3111 | std::set<handlerton *> *post_ddl_htons, | ||
| 3112 | Foreign_key_parents_invalidator *fk_invalidator, | ||
| 3113 | std::vector<MDL_ticket *> *safe_to_release_mdl) { | ||
| 3114 |
1/2✓ Branch 0 taken 156486 times.
✗ Branch 1 not taken.
|
156486 | dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client()); |
| 3115 |
1/2✓ Branch 0 taken 156486 times.
✗ Branch 1 not taken.
|
156486 | Drop_tables_ctx drop_ctx(if_exists, drop_temporary, drop_database); |
| 3116 | 156486 | std::vector<MDL_ticket *> safe_to_release_mdl_atomic; | |
| 3117 | |||
| 3118 | 156486 | bool default_db_doesnt_exist = false; | |
| 3119 | |||
| 3120 |
1/2✓ Branch 0 taken 156486 times.
✗ Branch 1 not taken.
|
156486 | DBUG_TRACE; |
| 3121 | |||
| 3122 | 156486 | *dropped_non_atomic_flag = false; | |
| 3123 | |||
| 3124 |
3/4✓ Branch 0 taken 156486 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 156480 times.
|
156486 | if (rm_table_sort_into_groups(thd, &drop_ctx, tables)) return true; |
| 3125 | |||
| 3126 | /* | ||
| 3127 | Figure out in which situation we are regarding GTID and different | ||
| 3128 | table groups. | ||
| 3129 | */ | ||
| 3130 |
3/4✓ Branch 0 taken 156480 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 156474 times.
|
156480 | if (rm_table_eval_gtid_and_table_groups_state(thd, &drop_ctx)) return true; |
| 3131 | |||
| 3132 |
7/8✓ Branch 0 taken 131267 times.
✓ Branch 1 taken 25207 times.
✓ Branch 2 taken 131267 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1038 times.
✓ Branch 5 taken 130229 times.
✓ Branch 6 taken 1038 times.
✓ Branch 7 taken 155436 times.
|
156474 | if (!drop_ctx.if_exists && drop_ctx.has_any_nonexistent_tables()) { |
| 3133 | /* | ||
| 3134 | No IF EXISTS clause and some non-existing tables. | ||
| 3135 | |||
| 3136 | Fail before dropping any tables. This gives us nice "atomic" (succeed | ||
| 3137 | or don't drop anything) behavior for most common failure scenario even | ||
| 3138 | for tables which don't support atomic DDL. | ||
| 3139 | |||
| 3140 | Do this check after getting full list of missing tables to produce | ||
| 3141 | better error message. | ||
| 3142 | */ | ||
| 3143 | 1038 | String wrong_tables; | |
| 3144 | |||
| 3145 |
4/6✓ Branch 0 taken 1038 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1038 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1097 times.
✓ Branch 5 taken 1038 times.
|
2135 | for (TABLE_LIST *table : drop_ctx.nonexistent_tables) { |
| 3146 |
3/4✓ Branch 0 taken 59 times.
✓ Branch 1 taken 1038 times.
✓ Branch 2 taken 59 times.
✗ Branch 3 not taken.
|
1097 | if (wrong_tables.length()) wrong_tables.append(','); |
| 3147 |
1/2✓ Branch 0 taken 1097 times.
✗ Branch 1 not taken.
|
1097 | append_table_name(&wrong_tables, table); |
| 3148 | } | ||
| 3149 | |||
| 3150 |
2/4✓ Branch 0 taken 1038 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1038 times.
✗ Branch 3 not taken.
|
1038 | my_error(ER_BAD_TABLE_ERROR, MYF(0), wrong_tables.c_ptr()); |
| 3151 | 1038 | return true; | |
| 3152 | 1038 | } | |
| 3153 | |||
| 3154 | /* Check if we are about to violate any foreign keys. */ | ||
| 3155 |
3/4✓ Branch 0 taken 155436 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 155420 times.
|
155436 | if (rm_table_check_fks(thd, &drop_ctx)) return true; |
| 3156 | |||
| 3157 |
7/8✓ Branch 0 taken 25197 times.
✓ Branch 1 taken 130223 times.
✓ Branch 2 taken 25197 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8927 times.
✓ Branch 5 taken 16270 times.
✓ Branch 6 taken 8927 times.
✓ Branch 7 taken 146493 times.
|
155420 | if (drop_ctx.if_exists && drop_ctx.has_any_nonexistent_tables()) { |
| 3158 |
4/6✓ Branch 0 taken 8927 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8927 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11015 times.
✓ Branch 5 taken 8927 times.
|
19942 | for (TABLE_LIST *table : drop_ctx.nonexistent_tables) { |
| 3159 | 11015 | String tbl_name; | |
| 3160 |
1/2✓ Branch 0 taken 11015 times.
✗ Branch 1 not taken.
|
11015 | append_table_name(&tbl_name, table); |
| 3161 |
3/6✓ Branch 0 taken 11015 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11015 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11015 times.
✗ Branch 5 not taken.
|
11015 | push_warning_printf(thd, Sql_condition::SL_NOTE, ER_BAD_TABLE_ERROR, |
| 3162 | ER_THD(thd, ER_BAD_TABLE_ERROR), tbl_name.c_ptr()); | ||
| 3163 | 11015 | } | |
| 3164 | } | ||
| 3165 | |||
| 3166 | /* Non-existent temporary tables with IF EXISTS do not need any | ||
| 3167 | further processing */ | ||
| 3168 |
7/8✓ Branch 0 taken 25197 times.
✓ Branch 1 taken 130223 times.
✓ Branch 2 taken 25197 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 750 times.
✓ Branch 5 taken 24447 times.
✓ Branch 6 taken 750 times.
✓ Branch 7 taken 154670 times.
|
155420 | if (drop_ctx.if_exists && drop_ctx.has_tmp_nonexistent_tables()) { |
| 3169 |
1/2✓ Branch 0 taken 750 times.
✗ Branch 1 not taken.
|
750 | drop_ctx.nonexistent_tables.clear(); |
| 3170 | |||
| 3171 | /* If such tables were all we had, there is nothing else to do */ | ||
| 3172 |
1/2✓ Branch 0 taken 750 times.
✗ Branch 1 not taken.
|
750 | if (!drop_ctx.has_base_atomic_tables() && |
| 3173 |
2/4✓ Branch 0 taken 750 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 750 times.
✗ Branch 3 not taken.
|
750 | !drop_ctx.has_base_non_atomic_tables() && |
| 3174 |
3/4✓ Branch 0 taken 750 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 724 times.
✓ Branch 3 taken 26 times.
|
750 | !drop_ctx.has_tmp_trans_tables() && |
| 3175 |
8/12✓ Branch 0 taken 750 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 724 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 701 times.
✓ Branch 5 taken 23 times.
✓ Branch 6 taken 701 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 701 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 701 times.
✓ Branch 11 taken 49 times.
|
1500 | !drop_ctx.has_tmp_non_trans_tables() && !drop_ctx.has_views()) { |
| 3176 | 701 | return false; | |
| 3177 | } | ||
| 3178 | } | ||
| 3179 | |||
| 3180 | /* | ||
| 3181 | Check early if default database exists. We don't want code responsible | ||
| 3182 | for dropping temporary tables fail due to this check after some tables | ||
| 3183 | were dropped already. | ||
| 3184 | */ | ||
| 3185 |
2/2✓ Branch 0 taken 154121 times.
✓ Branch 1 taken 598 times.
|
154719 | if (thd->db().str != nullptr) { |
| 3186 | 154121 | bool exists = false; | |
| 3187 |
2/4✓ Branch 0 taken 154121 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 154121 times.
|
154121 | if (dd::schema_exists(thd, thd->db().str, &exists)) return true; |
| 3188 | 154121 | default_db_doesnt_exist = !exists; | |
| 3189 | } | ||
| 3190 | |||
| 3191 | MEM_ROOT foreach_table_root(key_memory_rm_table_foreach_root, | ||
| 3192 | 154719 | MEM_ROOT_BLOCK_SIZE); | |
| 3193 | |||
| 3194 |
3/4✓ Branch 0 taken 154719 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 33863 times.
✓ Branch 3 taken 120856 times.
|
154719 | if (drop_ctx.has_base_non_atomic_tables()) { |
| 3195 | /* | ||
| 3196 | Handle base tables in storage engines which don't support atomic DDL. | ||
| 3197 | |||
| 3198 | Their drop can't be rolled back in case of crash or error. So we drop | ||
| 3199 | each such table individually and write to binlog a single-table DROP | ||
| 3200 | TABLE statement corresponding to this action right after it. | ||
| 3201 | This increases chances of SE, data-dictionary and binary log being in | ||
| 3202 | sync if crash occurs. | ||
| 3203 | This also handles case of error/statement being killed in a natural | ||
| 3204 | way - by the time when error occurs we already have logged all drops | ||
| 3205 | which were successful. So we don't need to write the whole failed | ||
| 3206 | statement with error code to binary log. | ||
| 3207 | |||
| 3208 | Note that we process non-atomic tables before atomic ones in order to | ||
| 3209 | avoid situations when DROP TABLES for mixed set of tables will fail | ||
| 3210 | and leave changes to atomic, "transactional" tables around. | ||
| 3211 | */ | ||
| 3212 |
4/6✓ Branch 0 taken 33863 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 33863 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 37281 times.
✓ Branch 5 taken 33857 times.
|
71138 | for (TABLE_LIST *table : drop_ctx.base_non_atomic_tables) { |
| 3213 |
3/4✓ Branch 0 taken 37281 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 37275 times.
|
37281 | if (drop_base_table(thd, drop_ctx, table, false /* non-atomic */, nullptr, |
| 3214 | nullptr, safe_to_release_mdl, &foreach_table_root)) | ||
| 3215 | 6 | goto err_with_rollback; | |
| 3216 | |||
| 3217 | 37275 | *dropped_non_atomic_flag = true; | |
| 3218 | |||
| 3219 |
1/2✓ Branch 0 taken 37275 times.
✗ Branch 1 not taken.
|
37275 | drop_ctx.dropped_non_atomic.push_back(table); |
| 3220 | |||
| 3221 |
2/2✓ Branch 0 taken 37251 times.
✓ Branch 1 taken 24 times.
|
37275 | if (!drop_ctx.has_gtid_many_table_groups()) { |
| 3222 | /* | ||
| 3223 | We don't have GTID assigned, or we have GTID assigned and this is | ||
| 3224 | single-table DROP TABLE for this specific table. | ||
| 3225 | |||
| 3226 | Write single-table DROP TABLE statement to binary log. | ||
| 3227 | |||
| 3228 | Do this even if table was dropped as part of DROP DATABASE statement, | ||
| 3229 | as this descreases chance of things getting out of sync in case of | ||
| 3230 | crash. | ||
| 3231 | */ | ||
| 3232 |
2/2✓ Branch 0 taken 1171 times.
✓ Branch 1 taken 36080 times.
|
37251 | if (drop_ctx.drop_database) { |
| 3233 |
2/2✓ Branch 0 taken 1163 times.
✓ Branch 1 taken 8 times.
|
1171 | if (mysql_bin_log.is_open()) { |
| 3234 | 1163 | String built_query; | |
| 3235 | |||
| 3236 | 1163 | built_query.set_charset(system_charset_info); | |
| 3237 |
1/2✓ Branch 0 taken 1163 times.
✗ Branch 1 not taken.
|
1163 | built_query.append("DROP TABLE IF EXISTS "); |
| 3238 | |||
| 3239 |
1/2✓ Branch 0 taken 1163 times.
✗ Branch 1 not taken.
|
1163 | append_identifier(thd, &built_query, table->table_name, |
| 3240 | table->table_name_length, system_charset_info, | ||
| 3241 | thd->charset()); | ||
| 3242 | |||
| 3243 |
1/2✓ Branch 0 taken 1163 times.
✗ Branch 1 not taken.
|
1163 | built_query.append(" /* generated by server */"); |
| 3244 | |||
| 3245 |
1/2✓ Branch 0 taken 1163 times.
✗ Branch 1 not taken.
|
1163 | thd->add_to_binlog_accessed_dbs(table->db); |
| 3246 | |||
| 3247 | 1163 | Query_log_event qinfo(thd, built_query.ptr(), built_query.length(), | |
| 3248 |
1/2✓ Branch 0 taken 1163 times.
✗ Branch 1 not taken.
|
2326 | false, true, false, 0); |
| 3249 | 1163 | qinfo.db = table->db; | |
| 3250 | 1163 | qinfo.db_len = table->db_length; | |
| 3251 | |||
| 3252 |
2/4✓ Branch 0 taken 1163 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1163 times.
|
1163 | if (mysql_bin_log.write_event(&qinfo)) goto err_with_rollback; |
| 3253 |
2/4✓ Branch 0 taken 1163 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1163 times.
✗ Branch 3 not taken.
|
1163 | } |
| 3254 | } else { | ||
| 3255 | Drop_tables_query_builder built_query( | ||
| 3256 | 36080 | thd, false /* no TEMPORARY */, drop_ctx.if_exists, | |
| 3257 |
1/2✓ Branch 0 taken 36080 times.
✗ Branch 1 not taken.
|
36080 | false /* stmt binlog cache */, false /* db exists */); |
| 3258 | |||
| 3259 |
1/2✓ Branch 0 taken 36080 times.
✗ Branch 1 not taken.
|
36080 | built_query.add_table(table); |
| 3260 | |||
| 3261 | 108240 | if (thd->variables.binlog_ddl_skip_rewrite || | |
| 3262 |
1/2✓ Branch 0 taken 36080 times.
✗ Branch 1 not taken.
|
36080 | thd->system_thread == SYSTEM_THREAD_SLAVE_SQL || |
| 3263 |
7/8✓ Branch 0 taken 36080 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30761 times.
✓ Branch 3 taken 5319 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 30760 times.
✓ Branch 6 taken 5320 times.
✓ Branch 7 taken 30760 times.
|
102921 | thd->system_thread == SYSTEM_THREAD_SLAVE_WORKER || |
| 3264 | 30761 | thd->is_binlog_applier()) { | |
| 3265 |
4/8✓ Branch 0 taken 5320 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5320 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5320 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 5320 times.
|
5320 | if (write_bin_log(thd, true, thd->query().str, thd->query().length, |
| 3266 | false)) { | ||
| 3267 | ✗ | goto err_with_rollback; | |
| 3268 | } | ||
| 3269 | |||
| 3270 | } else { | ||
| 3271 |
2/4✓ Branch 0 taken 30760 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 30760 times.
|
30760 | if (built_query.write_bin_log()) goto err_with_rollback; |
| 3272 | } | ||
| 3273 |
1/2✓ Branch 0 taken 36080 times.
✗ Branch 1 not taken.
|
36080 | } |
| 3274 | |||
| 3275 |
6/6✓ Branch 0 taken 5777 times.
✓ Branch 1 taken 31474 times.
✓ Branch 2 taken 140 times.
✓ Branch 3 taken 5637 times.
✓ Branch 4 taken 31614 times.
✓ Branch 5 taken 5637 times.
|
43028 | if (drop_ctx.has_no_gtid_single_table_group() || |
| 3276 | 5777 | drop_ctx.has_gtid_single_table_group()) { | |
| 3277 | /* | ||
| 3278 | This was a single-table DROP TABLE for this specific table. | ||
| 3279 | Commit change to binary log and/or mark GTID as executed instead. | ||
| 3280 | In theory, we also can update slave info atomically with binlog/ | ||
| 3281 | GTID changes, | ||
| 3282 | */ | ||
| 3283 |
5/10✓ Branch 0 taken 31614 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31614 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 31614 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 31614 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 31614 times.
|
31614 | if (trans_commit_stmt(thd) || trans_commit_implicit(thd)) |
| 3284 | ✗ | goto err_with_rollback; | |
| 3285 | } else { | ||
| 3286 | /* | ||
| 3287 | We don't have GTID assigned and this is not single-table | ||
| 3288 | DROP TABLE. Commit change to binary log (if there was any) | ||
| 3289 | and get GTID assigned for our single-table change. Do not | ||
| 3290 | release ANONYMOUS_GTID ownership yet as there can be more | ||
| 3291 | tables to drop and corresponding statements to write to | ||
| 3292 | binary log. Do not update slave info as there might be more | ||
| 3293 | groups. | ||
| 3294 | */ | ||
| 3295 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5637 times.
|
5637 | assert(drop_ctx.has_no_gtid_many_table_groups()); |
| 3296 | |||
| 3297 | 5637 | thd->is_commit_in_middle_of_statement = true; | |
| 3298 |
4/8✓ Branch 0 taken 5637 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5637 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5637 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 5637 times.
|
5637 | bool error = (trans_commit_stmt(thd) || trans_commit_implicit(thd)); |
| 3299 | 5637 | thd->is_commit_in_middle_of_statement = false; | |
| 3300 | |||
| 3301 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5637 times.
|
5637 | if (error) goto err_with_rollback; |
| 3302 | } | ||
| 3303 | } else { | ||
| 3304 | /* | ||
| 3305 | We have GTID assigned and several tables from SEs which don't support | ||
| 3306 | atomic DDL, or tables in different groups. Postpone writing to binary | ||
| 3307 | log/marking GTID as executed until all tables are processed. | ||
| 3308 | |||
| 3309 | Nothing to commit here as change to data-dictionary is already | ||
| 3310 | committed earlier. | ||
| 3311 | */ | ||
| 3312 | } | ||
| 3313 |
1/2✓ Branch 0 taken 37275 times.
✗ Branch 1 not taken.
|
37275 | foreach_table_root.ClearForReuse(); |
| 3314 | } | ||
| 3315 | } | ||
| 3316 | |||
| 3317 |
8/10✓ Branch 0 taken 154713 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 89490 times.
✓ Branch 3 taken 65223 times.
✓ Branch 4 taken 89490 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 89446 times.
✓ Branch 7 taken 44 times.
✓ Branch 8 taken 73294 times.
✓ Branch 9 taken 81419 times.
|
244159 | if (drop_ctx.has_base_atomic_tables() || drop_ctx.has_views() || |
| 3318 |
3/4✓ Branch 0 taken 89446 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8027 times.
✓ Branch 3 taken 81419 times.
|
89446 | drop_ctx.has_base_nonexistent_tables()) { |
| 3319 | /* | ||
| 3320 | Handle base tables in SEs which support atomic DDL, as well as views | ||
| 3321 | and non-existent tables. | ||
| 3322 | |||
| 3323 | Drop all these objects in SE and data-dictionary in a single atomic | ||
| 3324 | transaction. Write corresponding multi-table DROP TABLE statement to | ||
| 3325 | the binary log as part of the same transaction. | ||
| 3326 | */ | ||
| 3327 |
3/4✓ Branch 0 taken 73183 times.
✓ Branch 1 taken 111 times.
✓ Branch 2 taken 73183 times.
✗ Branch 3 not taken.
|
73294 | DEBUG_SYNC(thd, "rm_table_no_locks_before_delete_table"); |
| 3328 |
4/6✓ Branch 0 taken 73294 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 73293 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
73294 | DBUG_EXECUTE_IF("sleep_before_no_locks_delete_table", my_sleep(100000);); |
| 3329 | |||
| 3330 |
4/6✓ Branch 0 taken 73294 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 73291 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
|
73294 | DBUG_EXECUTE_IF("rm_table_no_locks_abort_before_atomic_tables", { |
| 3331 | my_error(ER_UNKNOWN_ERROR, MYF(0)); | ||
| 3332 | goto err_with_rollback; | ||
| 3333 | }); | ||
| 3334 | |||
| 3335 |
4/6✓ Branch 0 taken 73291 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 73291 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 96430 times.
✓ Branch 5 taken 73273 times.
|
169703 | for (TABLE_LIST *table : drop_ctx.base_atomic_tables) { |
| 3336 |
3/4✓ Branch 0 taken 96429 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 96412 times.
|
96430 | if (drop_base_table(thd, drop_ctx, table, true /* atomic */, |
| 3337 | post_ddl_htons, fk_invalidator, | ||
| 3338 | &safe_to_release_mdl_atomic, &foreach_table_root)) { | ||
| 3339 | 17 | goto err_with_rollback; | |
| 3340 | } | ||
| 3341 |
1/2✓ Branch 0 taken 96412 times.
✗ Branch 1 not taken.
|
96412 | foreach_table_root.ClearForReuse(); |
| 3342 | } | ||
| 3343 | |||
| 3344 |
4/6✓ Branch 0 taken 73273 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 37 times.
✓ Branch 3 taken 73236 times.
✓ Branch 4 taken 37 times.
✗ Branch 5 not taken.
|
73273 | DBUG_EXECUTE_IF("rm_table_no_locks_abort_after_atomic_tables", { |
| 3345 | my_error(ER_UNKNOWN_ERROR, MYF(0)); | ||
| 3346 | goto err_with_rollback; | ||
| 3347 | }); | ||
| 3348 | |||
| 3349 |
4/6✓ Branch 0 taken 73236 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 73236 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 858 times.
✓ Branch 5 taken 73236 times.
|
74094 | for (TABLE_LIST *table : drop_ctx.views) { |
| 3350 | /* Check that we have an exclusive lock on the view to be dropped. */ | ||
| 3351 |
2/4✓ Branch 0 taken 858 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 858 times.
|
858 | assert(thd->mdl_context.owns_equal_or_stronger_lock( |
| 3352 | MDL_key::TABLE, table->db, table->table_name, MDL_EXCLUSIVE)); | ||
| 3353 | |||
| 3354 |
1/2✓ Branch 0 taken 858 times.
✗ Branch 1 not taken.
|
858 | tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db, table->table_name, |
| 3355 | false); | ||
| 3356 | |||
| 3357 | 858 | const dd::View *view = nullptr; | |
| 3358 |
4/8✓ Branch 0 taken 858 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 858 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 858 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 858 times.
|
858 | if (thd->dd_client()->acquire(table->db, table->table_name, &view)) |
| 3359 | ✗ | goto err_with_rollback; | |
| 3360 | |||
| 3361 | /* | ||
| 3362 | Since we drop views here only if called by DROP DATABASE: | ||
| 3363 | - We can safely skip marking depending views as invalid if they | ||
| 3364 | belong to the same database. | ||
| 3365 | - No need to log anything. | ||
| 3366 | */ | ||
| 3367 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 858 times.
|
858 | assert(drop_ctx.drop_database); |
| 3368 | |||
| 3369 |
3/6✓ Branch 0 taken 858 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 858 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 858 times.
|
1716 | if (thd->dd_client()->drop(view) || |
| 3370 |
2/4✓ Branch 0 taken 858 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 858 times.
|
858 | mark_referencing_views_invalid(thd, table, true, false, |
| 3371 | &foreach_table_root)) | ||
| 3372 | ✗ | goto err_with_rollback; | |
| 3373 | |||
| 3374 |
1/2✓ Branch 0 taken 858 times.
✗ Branch 1 not taken.
|
858 | foreach_table_root.ClearForReuse(); |
| 3375 | } | ||
| 3376 | |||
| 3377 | #ifndef NDEBUG | ||
| 3378 |
4/6✓ Branch 0 taken 73236 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 73236 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10260 times.
✓ Branch 5 taken 73236 times.
|
83496 | for (TABLE_LIST *table : drop_ctx.nonexistent_tables) { |
| 3379 | /* | ||
| 3380 | Check that we have an exclusive lock on the table which we were | ||
| 3381 | supposed drop. | ||
| 3382 | */ | ||
| 3383 |
2/4✓ Branch 0 taken 10260 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10260 times.
|
10260 | assert(thd->mdl_context.owns_equal_or_stronger_lock( |
| 3384 | MDL_key::TABLE, table->db, table->table_name, MDL_EXCLUSIVE)); | ||
| 3385 | } | ||
| 3386 | #endif | ||
| 3387 | |||
| 3388 |
3/4✓ Branch 0 taken 73127 times.
✓ Branch 1 taken 109 times.
✓ Branch 2 taken 73127 times.
✗ Branch 3 not taken.
|
73236 | DEBUG_SYNC(thd, "rm_table_no_locks_before_binlog"); |
| 3389 | |||
| 3390 | 73236 | int error = 0; | |
| 3391 | |||
| 3392 |
2/2✓ Branch 0 taken 70309 times.
✓ Branch 1 taken 2927 times.
|
73236 | if (drop_ctx.drop_database) { |
| 3393 | /* | ||
| 3394 | This is DROP DATABASE. | ||
| 3395 | |||
| 3396 | If we don't have GTID assigned removal of tables from this group will be | ||
| 3397 | logged as DROP DATABASE and committed atomically, together with removal | ||
| 3398 | of events and stored routines, by the caller. | ||
| 3399 | |||
| 3400 | The same thing should happen if we have GTID assigned and tables only | ||
| 3401 | from this group. | ||
| 3402 | |||
| 3403 | If we have GTID assigned and mix of tables from SEs which support atomic | ||
| 3404 | DDL and which don't support it we will still behave in similar way. | ||
| 3405 | If the whole statement succeeds removal of tables from all groups will | ||
| 3406 | be logged as single DROP DATABASE statement. In case of failure we will | ||
| 3407 | report special error, but in addition it makes sense to rollback all | ||
| 3408 | changes to tables in SEs supporting atomic DDL. | ||
| 3409 | |||
| 3410 | So do nothing here in all three cases described above. | ||
| 3411 | */ | ||
| 3412 |
2/2✓ Branch 0 taken 70301 times.
✓ Branch 1 taken 8 times.
|
70309 | } else if (!drop_ctx.has_gtid_many_table_groups()) { |
| 3413 | /* | ||
| 3414 | We don't have GTID assigned, or we have GTID assigned and our DROP | ||
| 3415 | TABLES only drops table from this group, so we have fully atomic | ||
| 3416 | multi-table DROP TABLES statement. | ||
| 3417 | |||
| 3418 | If we have not dropped any tables at all (we have only non-existing | ||
| 3419 | tables) we don't have transaction started. We can't use binlog's | ||
| 3420 | trx cache in this case as it requires active transaction with valid | ||
| 3421 | XID. | ||
| 3422 | */ | ||
| 3423 | Drop_tables_query_builder built_query( | ||
| 3424 | 70301 | thd, false /* no TEMPORARY */, drop_ctx.if_exists, | |
| 3425 | /* stmt or trx cache. */ | ||
| 3426 |
2/4✓ Branch 0 taken 70301 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 70301 times.
✗ Branch 3 not taken.
|
70301 | drop_ctx.has_base_atomic_tables(), false /* db exists */); |
| 3427 | |||
| 3428 |
1/2✓ Branch 0 taken 70301 times.
✗ Branch 1 not taken.
|
70301 | built_query.add_array(drop_ctx.base_atomic_tables); |
| 3429 |
1/2✓ Branch 0 taken 70301 times.
✗ Branch 1 not taken.
|
70301 | built_query.add_array(drop_ctx.nonexistent_tables); |
| 3430 | |||
| 3431 | 70301 | thd->thread_specific_used = true; | |
| 3432 | |||
| 3433 | 210888 | if (thd->variables.binlog_ddl_skip_rewrite || | |
| 3434 |
2/2✓ Branch 0 taken 70274 times.
✓ Branch 1 taken 12 times.
|
70286 | thd->system_thread == SYSTEM_THREAD_SLAVE_SQL || |
| 3435 |
8/8✓ Branch 0 taken 70286 times.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 61812 times.
✓ Branch 3 taken 8462 times.
✓ Branch 4 taken 39 times.
✓ Branch 5 taken 61773 times.
✓ Branch 6 taken 8528 times.
✓ Branch 7 taken 61773 times.
|
202399 | thd->system_thread == SYSTEM_THREAD_SLAVE_WORKER || |
| 3436 | 61812 | thd->is_binlog_applier()) { | |
| 3437 |
3/6✓ Branch 0 taken 8528 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8528 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 8528 times.
|
8528 | if (write_bin_log(thd, true, thd->query().str, thd->query().length, |
| 3438 |
2/4✓ Branch 0 taken 8528 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8528 times.
✗ Branch 3 not taken.
|
8528 | drop_ctx.has_base_atomic_tables())) { |
| 3439 | ✗ | goto err_with_rollback; | |
| 3440 | } | ||
| 3441 | |||
| 3442 | } else { | ||
| 3443 |
3/4✓ Branch 0 taken 61773 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 61771 times.
|
61773 | if (built_query.write_bin_log()) goto err_with_rollback; |
| 3444 | } | ||
| 3445 | |||
| 3446 |
6/6✓ Branch 0 taken 2703 times.
✓ Branch 1 taken 67596 times.
✓ Branch 2 taken 1425 times.
✓ Branch 3 taken 1278 times.
✓ Branch 4 taken 69021 times.
✓ Branch 5 taken 1278 times.
|
73002 | if (drop_ctx.has_no_gtid_single_table_group() || |
| 3447 | 2703 | drop_ctx.has_gtid_single_table_group()) { | |
| 3448 | /* | ||
| 3449 | This is fully atomic multi-table DROP TABLES. | ||
| 3450 | Commit changes to SEs, data-dictionary and binary log/or | ||
| 3451 | and mark GTID as executed/update slave info tables atomically. | ||
| 3452 | */ | ||
| 3453 |
5/8✓ Branch 0 taken 69021 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 69021 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 69000 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 68999 times.
|
69021 | error = (trans_commit_stmt(thd) || trans_commit_implicit(thd)); |
| 3454 | } else { | ||
| 3455 | /* | ||
| 3456 | We don't have GTID assigned and this is not fully-atomic DROP TABLES. | ||
| 3457 | Commit changes to SE, data-dictionary and binary log and get GTID | ||
| 3458 | assigned for our changes. | ||
| 3459 | Do not release ANONYMOUS_GTID ownership and update slave info yet | ||
| 3460 | as there can be more tables (e.g. temporary) to drop and corresponding | ||
| 3461 | statements to write to binary log. | ||
| 3462 | */ | ||
| 3463 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1278 times.
|
1278 | assert(drop_ctx.has_no_gtid_many_table_groups()); |
| 3464 | |||
| 3465 | 1278 | thd->is_commit_in_middle_of_statement = true; | |
| 3466 |
4/8✓ Branch 0 taken 1278 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1278 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1278 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1278 times.
|
1278 | error = (trans_commit_stmt(thd) || trans_commit_implicit(thd)); |
| 3467 | 1278 | thd->is_commit_in_middle_of_statement = false; | |
| 3468 | } | ||
| 3469 | |||
| 3470 |
4/4✓ Branch 0 taken 70277 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 22 times.
✓ Branch 3 taken 70255 times.
|
70278 | if (!error && thd->locked_tables_mode) |
| 3471 |
1/2✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
|
22 | safe_to_release_mdl->insert(safe_to_release_mdl->end(), |
| 3472 | safe_to_release_mdl_atomic.begin(), | ||
| 3473 | safe_to_release_mdl_atomic.end()); | ||
| 3474 |
2/2✓ Branch 0 taken 70278 times.
✓ Branch 1 taken 2 times.
|
70280 | } else { |
| 3475 | /* | ||
| 3476 | We have GTID assigned, some tables from SEs which don't support | ||
| 3477 | atomic DDL and some from SEs which do. | ||
| 3478 | |||
| 3479 | Postpone writing to binary log and marking GTID as executed until | ||
| 3480 | later stage. We also postpone committing removal of tables in SEs | ||
| 3481 | supporting atomic DDL and corresponding changes to the data- | ||
| 3482 | dictionary until the same stage. This allows to minimize change | ||
| 3483 | difference between SEs/data-dictionary and binary log in case of | ||
| 3484 | crash. | ||
| 3485 | |||
| 3486 | If crash occurs binary log won't contain any traces about removal | ||
| 3487 | of tables in both SEs support and not-supporting atomic DDL. | ||
| 3488 | And only tables in SEs not supporting atomic DDL will be missing | ||
| 3489 | from SEs and the data-dictionary. Since removal of tables in SEs | ||
| 3490 | supporting atomic DDL will be rolled back during recovery. | ||
| 3491 | */ | ||
| 3492 | } | ||
| 3493 | |||
| 3494 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 73212 times.
|
73213 | if (error) goto err_with_rollback; |
| 3495 | } | ||
| 3496 | |||
| 3497 |
6/6✓ Branch 0 taken 151442 times.
✓ Branch 1 taken 3189 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 151433 times.
✓ Branch 4 taken 9 times.
✓ Branch 5 taken 154622 times.
|
154631 | if (!drop_ctx.drop_database && drop_ctx.has_gtid_many_table_groups()) { |
| 3498 | /* | ||
| 3499 | We DROP TABLES statement with GTID assigned and either several tables | ||
| 3500 | from SEs which don't support atomic DDL, or at least one table from | ||
| 3501 | such SE and some tables from SEs which do support atomic DDL. | ||
| 3502 | |||
| 3503 | We have postponed write to binlog earlier. Now it is time to do it. | ||
| 3504 | |||
| 3505 | If we don't have active transaction at this point (i.e. no tables | ||
| 3506 | in SE supporting atomic DDL were dropped) we can't use binlog's trx | ||
| 3507 | cache for this. as it requires active transaction with valid XID. | ||
| 3508 | If we have active transaction (i.e. some tables in SE supporting | ||
| 3509 | atomic DDL were dropped) we have to use trx cache to ensure that | ||
| 3510 | our transaction is properly recovered in case of crash/restart. | ||
| 3511 | */ | ||
| 3512 | Drop_tables_query_builder built_query( | ||
| 3513 | 9 | thd, false /* no TEMPORARY */, drop_ctx.if_exists, | |
| 3514 | /* trx or stmt cache */ | ||
| 3515 |
2/4✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
|
9 | drop_ctx.has_base_atomic_tables(), false /* db exists */); |
| 3516 | |||
| 3517 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
9 | built_query.add_array(drop_ctx.base_non_atomic_tables); |
| 3518 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
9 | built_query.add_array(drop_ctx.base_atomic_tables); |
| 3519 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
9 | built_query.add_array(drop_ctx.nonexistent_tables); |
| 3520 | |||
| 3521 |
2/4✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
|
9 | if (built_query.write_bin_log()) goto err_with_rollback; |
| 3522 | |||
| 3523 | /* | ||
| 3524 | Commit our changes to the binary log (if any) and mark GTID | ||
| 3525 | as executed. This also commits removal of tables in SEs | ||
| 3526 | supporting atomic DDL from SE and the data-dictionary. | ||
| 3527 | In theory, we can update slave info atomically with binlog/GTID | ||
| 3528 | changes here. | ||
| 3529 | */ | ||
| 3530 |
5/10✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 9 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 9 times.
|
9 | if (trans_commit_stmt(thd) || trans_commit_implicit(thd)) |
| 3531 | ✗ | goto err_with_rollback; | |
| 3532 | |||
| 3533 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
|
9 | if (thd->locked_tables_mode) |
| 3534 | ✗ | safe_to_release_mdl->insert(safe_to_release_mdl->end(), | |
| 3535 | safe_to_release_mdl_atomic.begin(), | ||
| 3536 | safe_to_release_mdl_atomic.end()); | ||
| 3537 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
9 | } |
| 3538 | |||
| 3539 |
2/2✓ Branch 0 taken 151442 times.
✓ Branch 1 taken 3189 times.
|
154631 | if (!drop_ctx.drop_database) { |
| 3540 | /* | ||
| 3541 | Unless this is DROP DATABASE removal of tables in SEs | ||
| 3542 | supporting foreign keys is already committed at this point. | ||
| 3543 | So we can invalidate cache entries for parent tables. | ||
| 3544 | */ | ||
| 3545 |
1/2✓ Branch 0 taken 151442 times.
✗ Branch 1 not taken.
|
151442 | fk_invalidator->invalidate(thd); |
| 3546 | } | ||
| 3547 | |||
| 3548 | /* | ||
| 3549 | Dropping of temporary tables cannot be rolled back. On the other hand it | ||
| 3550 | can't fail at this stage. So to get nice error handling behavior | ||
| 3551 | (either fully succeed or fail and do nothing (if there are no tables | ||
| 3552 | which don't support atomic DDL)) we process such tables after we are | ||
| 3553 | done with base tables. | ||
| 3554 | |||
| 3555 | DROP TEMPORARY TABLES does not commit an ongoing transaction. So in | ||
| 3556 | some circumstances we must binlog changes to non-transactional | ||
| 3557 | ahead of transaction (so we need to tell binlog that these changes | ||
| 3558 | are non-transactional), while changes to transactional tables | ||
| 3559 | should be binlogged as part of transaction. | ||
| 3560 | */ | ||
| 3561 |
3/4✓ Branch 0 taken 154631 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5622 times.
✓ Branch 3 taken 149009 times.
|
154631 | if (drop_ctx.has_tmp_non_trans_tables()) { |
| 3562 |
4/6✓ Branch 0 taken 5622 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5622 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5988 times.
✓ Branch 5 taken 5622 times.
|
11610 | for (auto *table : drop_ctx.tmp_non_trans_tables) { |
| 3563 | /* | ||
| 3564 | Don't check THD::killed flag. We can't rollback deletion of | ||
| 3565 | temporary table, so aborting on KILL will make DROP TABLES | ||
| 3566 | less atomic. | ||
| 3567 | OTOH it is unlikely that we have many temporary tables to drop | ||
| 3568 | so being immune to KILL is not that horrible in most cases. | ||
| 3569 | */ | ||
| 3570 |
1/2✓ Branch 0 taken 5988 times.
✗ Branch 1 not taken.
|
5988 | drop_temporary_table(thd, table); |
| 3571 | } | ||
| 3572 |
1/2✓ Branch 0 taken 5622 times.
✗ Branch 1 not taken.
|
5622 | thd->get_transaction()->mark_dropped_temp_table(Transaction_ctx::STMT); |
| 3573 | } | ||
| 3574 | |||
| 3575 |
3/4✓ Branch 0 taken 154631 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 684 times.
✓ Branch 3 taken 153947 times.
|
154631 | if (drop_ctx.has_tmp_non_trans_tables_to_binlog()) { |
| 3576 |
2/4✓ Branch 0 taken 684 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 684 times.
|
684 | assert(drop_ctx.has_tmp_non_trans_tables()); |
| 3577 | /* | ||
| 3578 | Handle non-transactional temporary tables. | ||
| 3579 | */ | ||
| 3580 | |||
| 3581 | /* DROP DATABASE doesn't deal with temporary tables. */ | ||
| 3582 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 684 times.
|
684 | assert(!drop_ctx.drop_database); |
| 3583 | |||
| 3584 | /* | ||
| 3585 | If default database does not exist, set | ||
| 3586 | 'is_drop_tmp_if_exists_with_no_defaultdb flag to 'true', | ||
| 3587 | so that the 'DROP TEMPORARY TABLE IF EXISTS' command is logged | ||
| 3588 | with a fully-qualified table name and we don't write "USE db" | ||
| 3589 | prefix. | ||
| 3590 | */ | ||
| 3591 | 684 | const bool is_drop_tmp_if_exists_with_no_defaultdb = | |
| 3592 |
3/4✓ Branch 0 taken 398 times.
✓ Branch 1 taken 286 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 398 times.
|
684 | (drop_ctx.if_exists && default_db_doesnt_exist); |
| 3593 | Drop_tables_query_builder built_query( | ||
| 3594 | 684 | thd, true /* DROP TEMPORARY */, drop_ctx.if_exists, | |
| 3595 |
1/2✓ Branch 0 taken 684 times.
✗ Branch 1 not taken.
|
684 | false /* stmt cache */, is_drop_tmp_if_exists_with_no_defaultdb); |
| 3596 | |||
| 3597 |
1/2✓ Branch 0 taken 684 times.
✗ Branch 1 not taken.
|
684 | built_query.add_array(drop_ctx.tmp_non_trans_tables_to_binlog); |
| 3598 | /* | ||
| 3599 | If there are no transactional temporary tables to be dropped | ||
| 3600 | add non-existent tables to this group. This ensures that on | ||
| 3601 | slave we won't split DROP TEMPORARY TABLES even if some tables | ||
| 3602 | are missing on it (which is no-no for GTID mode). | ||
| 3603 | */ | ||
| 3604 |
7/8✓ Branch 0 taken 555 times.
✓ Branch 1 taken 129 times.
✓ Branch 2 taken 555 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 548 times.
✓ Branch 5 taken 7 times.
✓ Branch 6 taken 548 times.
✓ Branch 7 taken 136 times.
|
684 | if (drop_ctx.drop_temporary && !drop_ctx.has_tmp_trans_tables()) |
| 3605 |
1/2✓ Branch 0 taken 548 times.
✗ Branch 1 not taken.
|
548 | built_query.add_array(drop_ctx.nonexistent_tables); |
| 3606 | |||
| 3607 | 684 | thd->thread_specific_used = true; | |
| 3608 | |||
| 3609 |
2/4✓ Branch 0 taken 684 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 684 times.
|
684 | if (built_query.write_bin_log()) goto err_with_rollback; |
| 3610 | |||
| 3611 |
2/2✓ Branch 0 taken 668 times.
✓ Branch 1 taken 16 times.
|
684 | if (!drop_ctx.has_gtid_single_table_group()) { |
| 3612 | /* | ||
| 3613 | We don't have GTID assigned. If we are not inside of transaction | ||
| 3614 | commit transaction in binary log to get one for our statement. | ||
| 3615 | */ | ||
| 3616 |
5/6✓ Branch 0 taken 668 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 577 times.
✓ Branch 3 taken 91 times.
✓ Branch 4 taken 577 times.
✓ Branch 5 taken 91 times.
|
668 | if (mysql_bin_log.is_open() && !thd->in_active_multi_stmt_transaction()) { |
| 3617 | /* | ||
| 3618 | The single purpose of this hack is to generate GTID for the DROP | ||
| 3619 | TEMPORARY TABLES statement we just have written. | ||
| 3620 | |||
| 3621 | Some notes about it: | ||
| 3622 | |||
| 3623 | *) if the binary log is closed GTIDs are not generated, so there is | ||
| 3624 | no point in the below "commit". | ||
| 3625 | *) thd->in_active_multi_stmt_transaction() is true means that there | ||
| 3626 | is an active transaction with some changes to transactional tables | ||
| 3627 | and in binlog transactional cache. Doing "commit" in such a case | ||
| 3628 | will commit these changes in SE and flush binlog's cache to disk, | ||
| 3629 | so can not be allowed. | ||
| 3630 | OTOH, when thd->in_active_multi_stmt_transaction() false and | ||
| 3631 | thd->in_multi_stmt_transaction_mode() is true there is | ||
| 3632 | transaction from user's point of view. However there were no | ||
| 3633 | changes to transactional tables to commit (all changes were only | ||
| 3634 | to non-transactional tables) and nothing in binlog transactional | ||
| 3635 | cache (all changes to non-transactional tables were written to | ||
| 3636 | binlog directly). Calling "commit" in this case won't do anything | ||
| 3637 | besides generating GTID and can be allowed. | ||
| 3638 | *) We use MYSQL_BIN_LOG::commit() and not trans_commit_implicit(), | ||
| 3639 | for example, because we don't want to end user's explicitly | ||
| 3640 | started transaction. | ||
| 3641 | *) In theory we can allow to update slave info here by not raising | ||
| 3642 | THD::is_commit_in_middle_of_statement flag if we are in | ||
| 3643 | no-GTID-single-group case. However there is little benefit from | ||
| 3644 | it as dropping of temporary tables should not fail. | ||
| 3645 | |||
| 3646 | TODO: Consider if there is some better way to achieve this. | ||
| 3647 | For example, can we use trans_commit_implicit() to split | ||
| 3648 | out temporary parts from DROP TABLES statement or when | ||
| 3649 | splitting DROP TEMPORARY TABLES and there is no explicit | ||
| 3650 | user transaction. And just write two temporary parts | ||
| 3651 | to appropriate caches in case when DROP TEMPORARY is used | ||
| 3652 | inside of user's transaction? | ||
| 3653 | */ | ||
| 3654 | 577 | thd->is_commit_in_middle_of_statement = true; | |
| 3655 |
1/2✓ Branch 0 taken 577 times.
✗ Branch 1 not taken.
|
577 | bool error = mysql_bin_log.commit(thd, true); |
| 3656 | 577 | thd->is_commit_in_middle_of_statement = false; | |
| 3657 | |||
| 3658 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 577 times.
|
577 | if (error) goto err_with_rollback; |
| 3659 | } | ||
| 3660 | } else { | ||
| 3661 | /* | ||
| 3662 | We have GTID assigned. Rely on commit at the end of statement or | ||
| 3663 | transaction to flush changes to binary log and mark GTID as executed. | ||
| 3664 | */ | ||
| 3665 | } | ||
| 3666 |
1/2✓ Branch 0 taken 684 times.
✗ Branch 1 not taken.
|
684 | } |
| 3667 | |||
| 3668 |
3/4✓ Branch 0 taken 154631 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 43647 times.
✓ Branch 3 taken 110984 times.
|
154631 | if (drop_ctx.has_tmp_trans_tables()) { |
| 3669 |
4/6✓ Branch 0 taken 43647 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 43647 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 43821 times.
✓ Branch 5 taken 43647 times.
|
87468 | for (auto *table : drop_ctx.tmp_trans_tables) { |
| 3670 | /* | ||
| 3671 | Don't check THD::killed flag. We can't rollback deletion of | ||
| 3672 | temporary table, so aborting on KILL will make DROP TABLES | ||
| 3673 | less atomic. | ||
| 3674 | OTOH it is unlikely that we have many temporary tables to drop | ||
| 3675 | so being immune to KILL is not that horrible in most cases. | ||
| 3676 | */ | ||
| 3677 |
1/2✓ Branch 0 taken 43821 times.
✗ Branch 1 not taken.
|
43821 | drop_temporary_table(thd, table); |
| 3678 | } | ||
| 3679 |
1/2✓ Branch 0 taken 43647 times.
✗ Branch 1 not taken.
|
43647 | thd->get_transaction()->mark_dropped_temp_table(Transaction_ctx::STMT); |
| 3680 | } | ||
| 3681 | |||
| 3682 |
5/6✓ Branch 0 taken 154631 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 153572 times.
✓ Branch 3 taken 1059 times.
✓ Branch 4 taken 1059 times.
✓ Branch 5 taken 153572 times.
|
308203 | if (drop_ctx.has_tmp_trans_tables_to_binlog() || |
| 3683 |
3/4✓ Branch 0 taken 153572 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 147969 times.
✓ Branch 3 taken 5603 times.
|
153572 | (!drop_ctx.has_tmp_non_trans_tables() && |
| 3684 |
2/4✓ Branch 0 taken 147969 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 147969 times.
|
147969 | drop_ctx.has_tmp_nonexistent_tables())) { |
| 3685 | /* | ||
| 3686 | Handle transactional temporary tables (and possibly non-existent | ||
| 3687 | temporary tables if they were not handled earlier). | ||
| 3688 | */ | ||
| 3689 | |||
| 3690 | /* DROP DATABASE doesn't deal with temporary tables. */ | ||
| 3691 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1059 times.
|
1059 | assert(!drop_ctx.drop_database); |
| 3692 | |||
| 3693 | /* | ||
| 3694 | If default database does not exist, set | ||
| 3695 | 'is_drop_tmp_if_exists_with_no_defaultdb flag to 'true', | ||
| 3696 | so that the 'DROP TEMPORARY TABLE IF EXISTS' command is logged | ||
| 3697 | with a fully-qualified table name and we don't write "USE db" | ||
| 3698 | prefix. | ||
| 3699 | |||
| 3700 | If we are executing DROP TABLES (without TEMPORARY clause) we | ||
| 3701 | can't use binlog's trx cache, as it requires activetransaction | ||
| 3702 | with valid XID. Luckily, trx cache is not strictly necessary in | ||
| 3703 | this case and DROP TEMPORARY TABLES where it is really needed is | ||
| 3704 | exempted from this rule. | ||
| 3705 | */ | ||
| 3706 | 1059 | const bool is_drop_tmp_if_exists_with_no_defaultdb = | |
| 3707 |
3/4✓ Branch 0 taken 621 times.
✓ Branch 1 taken 438 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 621 times.
|
1059 | (drop_ctx.if_exists && default_db_doesnt_exist); |
| 3708 | |||
| 3709 | Drop_tables_query_builder built_query( | ||
| 3710 | 1059 | thd, true /* DROP TEMPORARY */, drop_ctx.if_exists, | |
| 3711 | 1059 | drop_ctx.drop_temporary /* trx/stmt cache */, | |
| 3712 |
1/2✓ Branch 0 taken 1059 times.
✗ Branch 1 not taken.
|
1059 | is_drop_tmp_if_exists_with_no_defaultdb); |
| 3713 | |||
| 3714 |
1/2✓ Branch 0 taken 1059 times.
✗ Branch 1 not taken.
|
1059 | built_query.add_array(drop_ctx.tmp_trans_tables_to_binlog); |
| 3715 | |||
| 3716 | /* | ||
| 3717 | Add non-existent temporary tables to this group if there are some | ||
| 3718 | and they were not handled earlier. | ||
| 3719 | This ensures that on slave we won't split DROP TEMPORARY TABLES | ||
| 3720 | even if some tables are missing on it (which is no-no for GTID mode). | ||
| 3721 | */ | ||
| 3722 |
2/2✓ Branch 0 taken 859 times.
✓ Branch 1 taken 200 times.
|
1059 | if (drop_ctx.drop_temporary) |
| 3723 |
1/2✓ Branch 0 taken 859 times.
✗ Branch 1 not taken.
|
859 | built_query.add_array(drop_ctx.nonexistent_tables); |
| 3724 | |||
| 3725 | 1059 | thd->thread_specific_used = true; | |
| 3726 | |||
| 3727 |
2/4✓ Branch 0 taken 1059 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1059 times.
|
1059 | if (built_query.write_bin_log()) goto err_with_rollback; |
| 3728 | |||
| 3729 |
2/2✓ Branch 0 taken 1034 times.
✓ Branch 1 taken 25 times.
|
1059 | if (!drop_ctx.has_gtid_single_table_group()) { |
| 3730 | /* | ||
| 3731 | We don't have GTID assigned. If we are not inside of transaction | ||
| 3732 | commit transaction in binary log to get one for our statement. | ||
| 3733 | */ | ||
| 3734 |
5/6✓ Branch 0 taken 1034 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 909 times.
✓ Branch 3 taken 125 times.
✓ Branch 4 taken 909 times.
✓ Branch 5 taken 125 times.
|
1034 | if (mysql_bin_log.is_open() && !thd->in_active_multi_stmt_transaction()) { |
| 3735 | /* | ||
| 3736 | See the rationale for the hack with "commit" above. | ||
| 3737 | */ | ||
| 3738 | 909 | thd->is_commit_in_middle_of_statement = true; | |
| 3739 |
1/2✓ Branch 0 taken 909 times.
✗ Branch 1 not taken.
|
909 | bool error = mysql_bin_log.commit(thd, true); |
| 3740 | 909 | thd->is_commit_in_middle_of_statement = false; | |
| 3741 | |||
| 3742 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 909 times.
|
909 | if (error) goto err_with_rollback; |
| 3743 | } | ||
| 3744 | } else { | ||
| 3745 | /* | ||
| 3746 | We have GTID assigned. Rely on commit at the end of statement or | ||
| 3747 | transaction to flush changes to binary log and mark GTID as executed. | ||
| 3748 | */ | ||
| 3749 | } | ||
| 3750 |
1/2✓ Branch 0 taken 1059 times.
✗ Branch 1 not taken.
|
1059 | } |
| 3751 | |||
| 3752 |
2/2✓ Branch 0 taken 151442 times.
✓ Branch 1 taken 3189 times.
|
154631 | if (!drop_ctx.drop_database) { |
| 3753 |
3/4✓ Branch 0 taken 62256 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 62258 times.
✓ Branch 3 taken 151440 times.
|
213698 | for (handlerton *hton : *post_ddl_htons) hton->post_ddl(thd); |
| 3754 | } | ||
| 3755 | |||
| 3756 | 154629 | return false; | |
| 3757 | |||
| 3758 | 66 | err_with_rollback: | |
| 3759 |
2/2✓ Branch 0 taken 41 times.
✓ Branch 1 taken 25 times.
|
66 | if (!drop_ctx.drop_database) { |
| 3760 | /* | ||
| 3761 | Be consistent with successful case. Roll back statement | ||
| 3762 | and call post-DDL hooks within this function. | ||
| 3763 | |||
| 3764 | Note that this will rollback deletion of tables in SEs | ||
| 3765 | supporting atomic DDL only. Tables in engines which | ||
| 3766 | don't support atomic DDL are completely gone at this | ||
| 3767 | point. | ||
| 3768 | */ | ||
| 3769 | |||
| 3770 |
4/4✓ Branch 0 taken 3 times.
✓ Branch 1 taken 38 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 38 times.
|
44 | if (drop_ctx.has_gtid_many_table_groups() && |
| 3771 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | drop_ctx.has_dropped_non_atomic()) { |
| 3772 | /* | ||
| 3773 | So far we have been postponing writing DROP TABLES statement for | ||
| 3774 | tables in engines not supporting atomic DDL. We are going to write | ||
| 3775 | it now and let it to consume GTID assigned. Hence rollback of | ||
| 3776 | tables deletion of in SEs supporting atomic DDL should not rollback | ||
| 3777 | GTID. Use guard class to disable this. | ||
| 3778 | */ | ||
| 3779 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Implicit_substatement_state_guard substatement_guard(thd); |
| 3780 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | trans_rollback_stmt(thd); |
| 3781 | /* | ||
| 3782 | Full rollback in case we have THD::transaction_rollback_request | ||
| 3783 | and to synchronize DD state in cache and on disk (as statement | ||
| 3784 | rollback doesn't clear DD cache of modified uncommitted objects). | ||
| 3785 | */ | ||
| 3786 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | trans_rollback(thd); |
| 3787 | 3 | } else { | |
| 3788 |
1/2✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
|
38 | trans_rollback_stmt(thd); |
| 3789 | /* | ||
| 3790 | Full rollback in case we have THD::transaction_rollback_request | ||
| 3791 | and to synchronize DD state in cache and on disk (as statement | ||
| 3792 | rollback doesn't clear DD cache of modified uncommitted objects). | ||
| 3793 | */ | ||
| 3794 |
1/2✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
|
38 | trans_rollback(thd); |
| 3795 | } | ||
| 3796 | |||
| 3797 |
3/4✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 31 times.
✓ Branch 3 taken 41 times.
|
72 | for (handlerton *hton : *post_ddl_htons) hton->post_ddl(thd); |
| 3798 | |||
| 3799 |
4/4✓ Branch 0 taken 3 times.
✓ Branch 1 taken 38 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 38 times.
|
44 | if (drop_ctx.has_gtid_many_table_groups() && |
| 3800 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | drop_ctx.has_dropped_non_atomic()) { |
| 3801 | /* | ||
| 3802 | We have some tables dropped in SEs which don't support atomic DDL for | ||
| 3803 | which there were no binlog events written so far. Now we are going to | ||
| 3804 | write DROP TABLES statement for them and mark GTID as executed. | ||
| 3805 | This is not totally correct since original statement is only partially | ||
| 3806 | executed, but is consistent with 5.7 behavior. | ||
| 3807 | |||
| 3808 | TODO: Long-term we probably should generate new slave-based GTID for | ||
| 3809 | this event, or report special error about partial execution. | ||
| 3810 | |||
| 3811 | We don't have active transaction at this point so we can't use binlog's | ||
| 3812 | trx cache for this. It requires active transaction with valid XID. | ||
| 3813 | |||
| 3814 | */ | ||
| 3815 | Drop_tables_query_builder built_query( | ||
| 3816 | 3 | thd, false /* no TEMPORARY */, drop_ctx.if_exists, | |
| 3817 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | false /* stmt cache*/, false /* db exists */); |
| 3818 | |||
| 3819 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | built_query.add_array(drop_ctx.dropped_non_atomic); |
| 3820 | |||
| 3821 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | (void)built_query.write_bin_log(); |
| 3822 | |||
| 3823 | // Write statement to binary log and mark GTID as executed. | ||
| 3824 | |||
| 3825 | // We need to turn off updating of slave info | ||
| 3826 | // without conflicting with GTID update. | ||
| 3827 | { | ||
| 3828 | 3 | Disable_slave_info_update_guard substatement_guard(thd); | |
| 3829 | |||
| 3830 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | (void)trans_commit_stmt(thd); |
| 3831 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | (void)trans_commit_implicit(thd); |
| 3832 | 3 | } | |
| 3833 | 3 | } | |
| 3834 | } | ||
| 3835 | 66 | return true; | |
| 3836 | 156462 | } | |
| 3837 | |||
| 3838 | /** | ||
| 3839 | Quickly remove a table. | ||
| 3840 | |||
| 3841 | @param thd Thread context. | ||
| 3842 | @param base The handlerton handle. | ||
| 3843 | @param db The database name. | ||
| 3844 | @param table_name The table name. | ||
| 3845 | @param flags Flags for build_table_filename(). | ||
| 3846 | |||
| 3847 | @note In case when NO_DD_COMMIT flag was used, the caller must rollback | ||
| 3848 | both statement and transaction on failure. This is necessary to | ||
| 3849 | revert results of handler::ha_delete_table() call in case when | ||
| 3850 | update to the data-dictionary which follows it fails. Also this must | ||
| 3851 | be done before any further accesses to DD. @sa dd::drop_table(). | ||
| 3852 | |||
| 3853 | @return False in case of success, True otherwise. | ||
| 3854 | */ | ||
| 3855 | |||
| 3856 | 19270 | bool quick_rm_table(THD *thd, handlerton *base, const char *db, | |
| 3857 | const char *table_name, uint flags) { | ||
| 3858 |
1/2✓ Branch 0 taken 19270 times.
✗ Branch 1 not taken.
|
19270 | DBUG_TRACE; |
| 3859 | |||
| 3860 | // Build the schema qualified table name, to be submitted to the handler. | ||
| 3861 | char path[FN_REFLEN + 1]; | ||
| 3862 |
1/2✓ Branch 0 taken 19270 times.
✗ Branch 1 not taken.
|
19270 | (void)build_table_filename(path, sizeof(path) - 1, db, table_name, "", flags); |
| 3863 | |||
| 3864 | 19270 | const dd::Table *table_def = nullptr; | |
| 3865 |
4/8✓ Branch 0 taken 19270 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19270 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 19270 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 19270 times.
|
19270 | if (thd->dd_client()->acquire(db, table_name, &table_def)) return true; |
| 3866 | |||
| 3867 | /* We try to remove non-existing tables in some scenarios. */ | ||
| 3868 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 19270 times.
|
19270 | if (!table_def) return false; |
| 3869 | |||
| 3870 |
2/4✓ Branch 0 taken 19256 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 19256 times.
|
19270 | if (ha_delete_table(thd, base, path, db, table_name, table_def, false)) |
| 3871 | ✗ | return true; | |
| 3872 | |||
| 3873 | // Remove the table object from the data dictionary. If this fails, the | ||
| 3874 | // DD operation is already rolled back, and we must return with an error. | ||
| 3875 | // Note that the DD operation is done after invoking the SE. This is | ||
| 3876 | // because the DDL code will handle situations where a table is present | ||
| 3877 | // in the DD while missing from the SE, but not the opposite. | ||
| 3878 |
5/10✓ Branch 0 taken 19256 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19256 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 19256 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 19256 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 19256 times.
✗ Branch 9 not taken.
|
19256 | if (!dd::get_dictionary()->is_dd_table_name(db, table_name)) { |
| 3879 |
1/2✓ Branch 0 taken 19256 times.
✗ Branch 1 not taken.
|
19256 | bool result = dd::drop_table(thd, db, table_name, *table_def); |
| 3880 |
2/2✓ Branch 0 taken 13072 times.
✓ Branch 1 taken 6184 times.
|
19256 | if (!(flags & NO_DD_COMMIT)) |
| 3881 |
1/2✓ Branch 0 taken 13072 times.
✗ Branch 1 not taken.
|
13072 | result = trans_intermediate_ddl_commit(thd, result); |
| 3882 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 19256 times.
|
19256 | if (result) { |
| 3883 | ✗ | assert(thd->is_error() || thd->killed); | |
| 3884 | ✗ | return true; | |
| 3885 | } | ||
| 3886 | } | ||
| 3887 | |||
| 3888 | 19256 | return false; | |
| 3889 | 19256 | } | |
| 3890 | |||
| 3891 | /* | ||
| 3892 | Sort keys according to the following properties, in decreasing order of | ||
| 3893 | importance: | ||
| 3894 | - PRIMARY KEY | ||
| 3895 | - UNIQUE with all columns NOT NULL | ||
| 3896 | - UNIQUE without partial segments | ||
| 3897 | - UNIQUE | ||
| 3898 | - without fulltext columns | ||
| 3899 | - without virtual generated columns | ||
| 3900 | |||
| 3901 | This allows us to | ||
| 3902 | - check for duplicate key values faster (PK and UNIQUE are first) | ||
| 3903 | - prioritize PKs | ||
| 3904 | - be sure that, if there is no PK, the set of UNIQUE keys candidate for | ||
| 3905 | promotion starts at number 0, and we can choose #0 as PK (it is required | ||
| 3906 | that PK has number 0). | ||
| 3907 | */ | ||
| 3908 | |||
| 3909 | namespace { | ||
| 3910 | |||
| 3911 | struct sort_keys { | ||
| 3912 | 1771266 | bool operator()(const KEY &a, const KEY &b) const { | |
| 3913 | // Sort UNIQUE before not UNIQUE. | ||
| 3914 |
2/2✓ Branch 0 taken 727788 times.
✓ Branch 1 taken 1043478 times.
|
1771266 | if ((a.flags ^ b.flags) & HA_NOSAME) return a.flags & HA_NOSAME; |
| 3915 | |||
| 3916 |
2/2✓ Branch 0 taken 771110 times.
✓ Branch 1 taken 272368 times.
|
1043478 | if (a.flags & HA_NOSAME) { |
| 3917 | // Sort UNIQUE NOT NULL keys before other UNIQUE keys. | ||
| 3918 |
2/2✓ Branch 0 taken 89575 times.
✓ Branch 1 taken 681535 times.
|
771110 | if ((a.flags ^ b.flags) & HA_NULL_PART_KEY) |
| 3919 | 89575 | return b.flags & HA_NULL_PART_KEY; | |
| 3920 | |||
| 3921 | // Sort PRIMARY KEY before other UNIQUE NOT NULL. | ||
| 3922 |
2/2✓ Branch 0 taken 43 times.
✓ Branch 1 taken 681492 times.
|
681535 | if (a.name == primary_key_name) return true; |
| 3923 |
2/2✓ Branch 0 taken 543394 times.
✓ Branch 1 taken 138098 times.
|
681492 | if (b.name == primary_key_name) return false; |
| 3924 | |||
| 3925 | // Sort keys don't containing partial segments before others. | ||
| 3926 |
2/2✓ Branch 0 taken 43 times.
✓ Branch 1 taken 138055 times.
|
138098 | if ((a.flags ^ b.flags) & HA_KEY_HAS_PART_KEY_SEG) |
| 3927 | 43 | return b.flags & HA_KEY_HAS_PART_KEY_SEG; | |
| 3928 | } | ||
| 3929 | |||
| 3930 |
2/2✓ Branch 0 taken 150 times.
✓ Branch 1 taken 410273 times.
|
410423 | if ((a.flags ^ b.flags) & HA_FULLTEXT) return b.flags & HA_FULLTEXT; |
| 3931 | |||
| 3932 |
2/2✓ Branch 0 taken 320 times.
✓ Branch 1 taken 409953 times.
|
410273 | if ((a.flags ^ b.flags) & HA_VIRTUAL_GEN_KEY) |
| 3933 | 320 | return b.flags & HA_VIRTUAL_GEN_KEY; | |
| 3934 | |||
| 3935 | /* | ||
| 3936 | Prefer original key order. usable_key_parts contains here | ||
| 3937 | the original key position. | ||
| 3938 | */ | ||
| 3939 | 409953 | return a.usable_key_parts < b.usable_key_parts; | |
| 3940 | } | ||
| 3941 | }; | ||
| 3942 | |||
| 3943 | } // namespace | ||
| 3944 | |||
| 3945 | /* | ||
| 3946 | Check TYPELIB (set or enum) for duplicates | ||
| 3947 | |||
| 3948 | SYNOPSIS | ||
| 3949 | check_duplicates_in_interval() | ||
| 3950 | thd Thread handle | ||
| 3951 | set_or_name "SET" or "ENUM" string for warning message | ||
| 3952 | name name of the checked column | ||
| 3953 | typelib list of values for the column | ||
| 3954 | dup_val_count returns count of duplicate elements | ||
| 3955 | |||
| 3956 | DESCRIPTION | ||
| 3957 | This function prints an warning for each value in list | ||
| 3958 | which has some duplicates on its right | ||
| 3959 | |||
| 3960 | RETURN VALUES | ||
| 3961 | 0 ok | ||
| 3962 | 1 Error | ||
| 3963 | */ | ||
| 3964 | |||
| 3965 | 897535 | static bool check_duplicates_in_interval(THD *thd, const char *set_or_name, | |
| 3966 | const char *name, TYPELIB *typelib, | ||
| 3967 | const CHARSET_INFO *cs, | ||
| 3968 | uint *dup_val_count) { | ||
| 3969 | 897535 | TYPELIB tmp = *typelib; | |
| 3970 | 897535 | const char **cur_value = typelib->type_names; | |
| 3971 | 897535 | unsigned int *cur_length = typelib->type_lengths; | |
| 3972 | 897535 | *dup_val_count = 0; | |
| 3973 | |||
| 3974 |
2/2✓ Branch 0 taken 4102091 times.
✓ Branch 1 taken 897524 times.
|
4999615 | for (; tmp.count > 1; cur_value++, cur_length++) { |
| 3975 | 4102091 | tmp.type_names++; | |
| 3976 | 4102091 | tmp.type_lengths++; | |
| 3977 | 4102091 | tmp.count--; | |
| 3978 |
3/4✓ Branch 0 taken 4102091 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 49 times.
✓ Branch 3 taken 4102042 times.
|
4102091 | if (find_type2(&tmp, *cur_value, *cur_length, cs)) { |
| 3979 |
1/2✓ Branch 0 taken 49 times.
✗ Branch 1 not taken.
|
49 | ErrConvString err(*cur_value, *cur_length, cs); |
| 3980 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 38 times.
|
49 | if (thd->is_strict_mode()) { |
| 3981 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
11 | my_error(ER_DUPLICATED_VALUE_IN_TYPE, MYF(0), name, err.ptr(), |
| 3982 | set_or_name); | ||
| 3983 | 11 | return true; | |
| 3984 | } | ||
| 3985 |
2/4✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 38 times.
✗ Branch 3 not taken.
|
38 | push_warning_printf(thd, Sql_condition::SL_NOTE, |
| 3986 | ER_DUPLICATED_VALUE_IN_TYPE, | ||
| 3987 | ER_THD(thd, ER_DUPLICATED_VALUE_IN_TYPE), name, | ||
| 3988 | err.ptr(), set_or_name); | ||
| 3989 | 38 | (*dup_val_count)++; | |
| 3990 | } | ||
| 3991 | } | ||
| 3992 | 897524 | return false; | |
| 3993 | } | ||
| 3994 | |||
| 3995 | /** | ||
| 3996 | Prepare a create_table instance for packing | ||
| 3997 | |||
| 3998 | @param thd Thread handle | ||
| 3999 | @param [in,out] sql_field field to prepare for packing | ||
| 4000 | @param table_flags table flags | ||
| 4001 | |||
| 4002 | @return true if error, false if ok | ||
| 4003 | */ | ||
| 4004 | |||
| 4005 | 6749923 | bool prepare_pack_create_field(THD *thd, Create_field *sql_field, | |
| 4006 | longlong table_flags) { | ||
| 4007 | unsigned int dup_val_count; | ||
| 4008 |
1/2✓ Branch 0 taken 6749939 times.
✗ Branch 1 not taken.
|
6749923 | DBUG_TRACE; |
| 4009 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6749939 times.
|
6749939 | assert(sql_field->charset); |
| 4010 | |||
| 4011 | 6749939 | sql_field->is_nullable = true; | |
| 4012 | 6749939 | sql_field->is_zerofill = false; | |
| 4013 | 6749939 | sql_field->is_unsigned = false; | |
| 4014 | |||
| 4015 |
8/8✓ Branch 0 taken 2829 times.
✓ Branch 1 taken 997433 times.
✓ Branch 2 taken 1293565 times.
✓ Branch 3 taken 214379 times.
✓ Branch 4 taken 844079 times.
✓ Branch 5 taken 53456 times.
✓ Branch 6 taken 65502 times.
✓ Branch 7 taken 3278696 times.
|
6749939 | switch (sql_field->sql_type) { |
| 4016 | 2829 | case MYSQL_TYPE_GEOMETRY: | |
| 4017 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2828 times.
|
2829 | if (!(table_flags & HA_CAN_GEOMETRY)) { |
| 4018 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "GEOMETRY"); |
| 4019 | 1 | return true; | |
| 4020 | } | ||
| 4021 | [[fallthrough]]; | ||
| 4022 | case MYSQL_TYPE_BLOB: | ||
| 4023 | case MYSQL_TYPE_MEDIUM_BLOB: | ||
| 4024 | case MYSQL_TYPE_TINY_BLOB: | ||
| 4025 | case MYSQL_TYPE_LONG_BLOB: | ||
| 4026 | case MYSQL_TYPE_JSON: | ||
| 4027 |
3/4✓ Branch 0 taken 392 times.
✓ Branch 1 taken 999869 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 392 times.
|
1000261 | assert(sql_field->auto_flags == Field::NONE || |
| 4028 | sql_field->auto_flags == Field::GENERATED_FROM_EXPRESSION); | ||
| 4029 | 1000261 | break; | |
| 4030 | 1293565 | case MYSQL_TYPE_VARCHAR: | |
| 4031 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1293565 times.
|
1293565 | if (table_flags & HA_NO_VARCHAR) { |
| 4032 | /* Convert VARCHAR to CHAR because handler is not yet up to date */ | ||
| 4033 | ✗ | sql_field->sql_type = MYSQL_TYPE_VAR_STRING; | |
| 4034 | ✗ | if (sql_field->max_display_width_in_codepoints() > | |
| 4035 | MAX_FIELD_CHARLENGTH) { | ||
| 4036 | ✗ | my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0), sql_field->field_name, | |
| 4037 | static_cast<ulong>(MAX_FIELD_CHARLENGTH)); | ||
| 4038 | ✗ | return true; | |
| 4039 | } | ||
| 4040 | } | ||
| 4041 | 1293565 | break; | |
| 4042 | 214379 | case MYSQL_TYPE_STRING: | |
| 4043 | 214379 | break; | |
| 4044 | 844079 | case MYSQL_TYPE_ENUM: | |
| 4045 |
3/4✓ Branch 0 taken 8 times.
✓ Branch 1 taken 844071 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
|
844079 | assert(sql_field->auto_flags == Field::NONE || |
| 4046 | sql_field->auto_flags == Field::GENERATED_FROM_EXPRESSION); | ||
| 4047 |
3/4✓ Branch 0 taken 844079 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 844075 times.
|
844079 | if (check_duplicates_in_interval(thd, "ENUM", sql_field->field_name, |
| 4048 | sql_field->interval, sql_field->charset, | ||
| 4049 | &dup_val_count)) | ||
| 4050 | 4 | return true; | |
| 4051 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 844074 times.
|
844075 | if (sql_field->interval->count > MAX_ENUM_VALUES) { |
| 4052 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_TOO_BIG_ENUM, MYF(0), sql_field->field_name); |
| 4053 | 1 | return true; | |
| 4054 | } | ||
| 4055 | 844074 | break; | |
| 4056 | 53456 | case MYSQL_TYPE_SET: | |
| 4057 |
3/4✓ Branch 0 taken 8 times.
✓ Branch 1 taken 53448 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
|
53456 | assert(sql_field->auto_flags == Field::NONE || |
| 4058 | sql_field->auto_flags == Field::GENERATED_FROM_EXPRESSION); | ||
| 4059 |
3/4✓ Branch 0 taken 53456 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 53449 times.
|
53456 | if (check_duplicates_in_interval(thd, "SET", sql_field->field_name, |
| 4060 | sql_field->interval, sql_field->charset, | ||
| 4061 | &dup_val_count)) | ||
| 4062 | 7 | return true; | |
| 4063 | /* Check that count of unique members is not more then 64 */ | ||
| 4064 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 53445 times.
|
53449 | if (sql_field->interval->count - dup_val_count > sizeof(longlong) * 8) { |
| 4065 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | my_error(ER_TOO_BIG_SET, MYF(0), sql_field->field_name); |
| 4066 | 4 | return true; | |
| 4067 | } | ||
| 4068 | 53445 | break; | |
| 4069 | 65502 | case MYSQL_TYPE_DATE: // Rest of string types | |
| 4070 | case MYSQL_TYPE_NEWDATE: | ||
| 4071 | case MYSQL_TYPE_TIME: | ||
| 4072 | case MYSQL_TYPE_DATETIME: | ||
| 4073 | case MYSQL_TYPE_TIME2: | ||
| 4074 | case MYSQL_TYPE_DATETIME2: | ||
| 4075 | case MYSQL_TYPE_NULL: | ||
| 4076 | case MYSQL_TYPE_BIT: | ||
| 4077 | 65502 | break; | |
| 4078 | 3278696 | case MYSQL_TYPE_TIMESTAMP: | |
| 4079 | case MYSQL_TYPE_TIMESTAMP2: | ||
| 4080 | case MYSQL_TYPE_NEWDECIMAL: | ||
| 4081 | default: | ||
| 4082 |
2/2✓ Branch 0 taken 4453 times.
✓ Branch 1 taken 3274243 times.
|
3278696 | if (sql_field->flags & ZEROFILL_FLAG) sql_field->is_zerofill = true; |
| 4083 |
2/2✓ Branch 0 taken 2116802 times.
✓ Branch 1 taken 1161894 times.
|
3278696 | if (sql_field->flags & UNSIGNED_FLAG) sql_field->is_unsigned = true; |
| 4084 | 3278696 | break; | |
| 4085 | } | ||
| 4086 | |||
| 4087 |
2/2✓ Branch 0 taken 4094346 times.
✓ Branch 1 taken 2655576 times.
|
6749922 | if (sql_field->flags & NOT_NULL_FLAG) sql_field->is_nullable = false; |
| 4088 | // Array fields are JSON fields, so override pack length | ||
| 4089 | 6749922 | sql_field->pack_length_override = | |
| 4090 |
2/2✓ Branch 0 taken 423 times.
✓ Branch 1 taken 6749499 times.
|
6749922 | sql_field->is_array ? (4 + portable_sizeof_char_ptr) : 0; |
| 4091 | |||
| 4092 | 6749922 | return false; | |
| 4093 | 6749939 | } | |
| 4094 | |||
| 4095 | 546871 | TYPELIB *create_typelib(MEM_ROOT *mem_root, Create_field *field_def) { | |
| 4096 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 546871 times.
|
546871 | if (!field_def->interval_list.elements) return nullptr; |
| 4097 | |||
| 4098 | TYPELIB *result = | ||
| 4099 |
1/2✓ Branch 0 taken 546871 times.
✗ Branch 1 not taken.
|
546871 | reinterpret_cast<TYPELIB *>(mem_root->Alloc(sizeof(TYPELIB))); |
| 4100 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 546871 times.
|
546871 | if (!result) return nullptr; |
| 4101 | |||
| 4102 | 546871 | result->count = field_def->interval_list.elements; | |
| 4103 | 546871 | result->name = ""; | |
| 4104 | |||
| 4105 | // Allocate type_names and type_lengths as one block. | ||
| 4106 | 546871 | size_t nbytes = (sizeof(char *) + sizeof(uint)) * (result->count + 1); | |
| 4107 | 546871 | if (!(result->type_names = | |
| 4108 |
2/4✓ Branch 0 taken 546871 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 546871 times.
|
546871 | reinterpret_cast<const char **>(mem_root->Alloc(nbytes)))) |
| 4109 | ✗ | return nullptr; | |
| 4110 | |||
| 4111 | 546871 | result->type_lengths = | |
| 4112 | 546871 | reinterpret_cast<uint *>(result->type_names + result->count + 1); | |
| 4113 | |||
| 4114 |
1/2✓ Branch 0 taken 546871 times.
✗ Branch 1 not taken.
|
546871 | List_iterator<String> it(field_def->interval_list); |
| 4115 |
2/2✓ Branch 0 taken 4242977 times.
✓ Branch 1 taken 546871 times.
|
4789848 | for (uint i = 0; i < result->count; i++) { |
| 4116 | size_t dummy; | ||
| 4117 | 4242977 | String *tmp = it++; | |
| 4118 | |||
| 4119 |
3/4✓ Branch 0 taken 4242977 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3982766 times.
✓ Branch 3 taken 260211 times.
|
4242977 | if (String::needs_conversion(tmp->length(), tmp->charset(), |
| 4120 | field_def->charset, &dummy)) { | ||
| 4121 | uint cnv_errs; | ||
| 4122 | 3982766 | String conv; | |
| 4123 |
1/2✓ Branch 0 taken 3982766 times.
✗ Branch 1 not taken.
|
3982766 | conv.copy(tmp->ptr(), tmp->length(), tmp->charset(), field_def->charset, |
| 4124 | &cnv_errs); | ||
| 4125 | |||
| 4126 |
1/2✓ Branch 0 taken 3982766 times.
✗ Branch 1 not taken.
|
3982766 | result->type_names[i] = strmake_root(mem_root, conv.ptr(), conv.length()); |
| 4127 | 3982766 | result->type_lengths[i] = conv.length(); | |
| 4128 | 3982766 | } else { | |
| 4129 | 260211 | result->type_names[i] = tmp->ptr(); | |
| 4130 | 260211 | result->type_lengths[i] = tmp->length(); | |
| 4131 | } | ||
| 4132 | |||
| 4133 | // Strip trailing spaces. | ||
| 4134 | 8485954 | size_t length = field_def->charset->cset->lengthsp( | |
| 4135 |
1/2✓ Branch 0 taken 4242977 times.
✗ Branch 1 not taken.
|
4242977 | field_def->charset, result->type_names[i], result->type_lengths[i]); |
| 4136 | 4242977 | result->type_lengths[i] = length; | |
| 4137 | 4242977 | (const_cast<char *>(result->type_names[i]))[length] = '\0'; | |
| 4138 | } | ||
| 4139 | 546871 | result->type_names[result->count] = nullptr; // End marker (char*) | |
| 4140 | 546871 | result->type_lengths[result->count] = 0; // End marker (uint) | |
| 4141 | |||
| 4142 | 546871 | field_def->interval_list.clear(); // Don't need interval_list anymore | |
| 4143 | 546871 | return result; | |
| 4144 | } | ||
| 4145 | |||
| 4146 | /** | ||
| 4147 | Prepare an instance of Create_field for field creation | ||
| 4148 | (fill all necessary attributes). Only used for stored programs. | ||
| 4149 | |||
| 4150 | @param[in] thd Thread handle | ||
| 4151 | @param[out] field_def An instance of initialized create_field | ||
| 4152 | |||
| 4153 | @return Error status. | ||
| 4154 | */ | ||
| 4155 | |||
| 4156 | 371770 | bool prepare_sp_create_field(THD *thd, Create_field *field_def) { | |
| 4157 |
2/2✓ Branch 0 taken 617 times.
✓ Branch 1 taken 371153 times.
|
371770 | if (field_def->sql_type == MYSQL_TYPE_SET) { |
| 4158 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 617 times.
|
617 | if (prepare_set_field(thd, field_def)) return true; |
| 4159 |
2/2✓ Branch 0 taken 12625 times.
✓ Branch 1 taken 358528 times.
|
371153 | } else if (field_def->sql_type == MYSQL_TYPE_ENUM) { |
| 4160 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12625 times.
|
12625 | if (prepare_enum_field(thd, field_def)) return true; |
| 4161 |
2/2✓ Branch 0 taken 64 times.
✓ Branch 1 taken 358464 times.
|
358528 | } else if (field_def->sql_type == MYSQL_TYPE_BIT) |
| 4162 | 64 | field_def->treat_bit_as_char = true; | |
| 4163 | |||
| 4164 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 371772 times.
|
371770 | if (prepare_blob_field(thd, field_def, false)) return true; |
| 4165 | |||
| 4166 | 371772 | return prepare_pack_create_field(thd, field_def, HA_CAN_GEOMETRY); | |
| 4167 | } | ||
| 4168 | |||
| 4169 | /** | ||
| 4170 | Get the character set from field object generated by the parser, using | ||
| 4171 | default values when not set. | ||
| 4172 | |||
| 4173 | @param sql_field The sql_field object | ||
| 4174 | @param create_info Info generated by parser | ||
| 4175 | @return character set | ||
| 4176 | */ | ||
| 4177 | 6416490 | const CHARSET_INFO *get_sql_field_charset(const Create_field *sql_field, | |
| 4178 | const HA_CREATE_INFO *create_info) { | ||
| 4179 |
2/2✓ Branch 0 taken 2188533 times.
✓ Branch 1 taken 4227957 times.
|
6416490 | const CHARSET_INFO *cs = sql_field->charset != nullptr |
| 4180 | ? sql_field->charset | ||
| 4181 | : create_info->default_table_charset; | ||
| 4182 | |||
| 4183 | /* | ||
| 4184 | The hidden ARRAY typed column that backs the multi-valued index, and is | ||
| 4185 | implemented as a JSON column, can only use the character sets | ||
| 4186 | my_charset_utf8mb4_0900_bin or binary. This column's charset should not | ||
| 4187 | be changed when altering the table_charset. | ||
| 4188 | (See Field_typed_array for more details). | ||
| 4189 | Also table_charset must not affect the BLOB fields, so don't allow to change | ||
| 4190 | my_charset_bin to something else. | ||
| 4191 | */ | ||
| 4192 |
4/4✓ Branch 0 taken 6416065 times.
✓ Branch 1 taken 425 times.
✓ Branch 2 taken 321657 times.
✓ Branch 3 taken 6094408 times.
|
6416490 | if (sql_field->is_array || cs == &my_charset_bin) return cs; |
| 4193 | |||
| 4194 | /* | ||
| 4195 | table_charset is set only in ALTER TABLE t1 CONVERT TO CHARACTER SET csname | ||
| 4196 | when we want to change character set for all varchar/char columns. | ||
| 4197 | */ | ||
| 4198 |
2/2✓ Branch 0 taken 20000 times.
✓ Branch 1 taken 6074408 times.
|
6094408 | if (create_info->table_charset != nullptr) return create_info->table_charset; |
| 4199 | |||
| 4200 | 6074408 | return cs; | |
| 4201 | } | ||
| 4202 | |||
| 4203 | /** | ||
| 4204 | Modifies the first column definition whose SQL type is TIMESTAMP | ||
| 4205 | by adding the features DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP. | ||
| 4206 | |||
| 4207 | @param column_definitions The list of column definitions, in the physical | ||
| 4208 | order in which they appear in the table. | ||
| 4209 | */ | ||
| 4210 | 197 | void promote_first_timestamp_column(List<Create_field> *column_definitions) { | |
| 4211 |
1/2✓ Branch 0 taken 197 times.
✗ Branch 1 not taken.
|
197 | List_iterator<Create_field> it(*column_definitions); |
| 4212 | Create_field *column_definition; | ||
| 4213 | |||
| 4214 |
2/2✓ Branch 0 taken 298 times.
✓ Branch 1 taken 127 times.
|
425 | while ((column_definition = it++) != nullptr) { |
| 4215 |
2/2✓ Branch 0 taken 292 times.
✓ Branch 1 taken 6 times.
|
298 | if (column_definition->sql_type == MYSQL_TYPE_TIMESTAMP || // TIMESTAMP |
| 4216 |
2/2✓ Branch 0 taken 64 times.
✓ Branch 1 taken 228 times.
|
292 | column_definition->sql_type == MYSQL_TYPE_TIMESTAMP2) // ms TIMESTAMP |
| 4217 | { | ||
| 4218 |
2/2✓ Branch 0 taken 56 times.
✓ Branch 1 taken 14 times.
|
70 | if ((column_definition->flags & NOT_NULL_FLAG) != 0 && // NOT NULL, |
| 4219 |
2/2✓ Branch 0 taken 37 times.
✓ Branch 1 taken 19 times.
|
56 | column_definition->constant_default == |
| 4220 | 37 | nullptr && // no constant default | |
| 4221 |
1/2✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
|
37 | column_definition->gcol_info == nullptr && // not a generated column |
| 4222 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 22 times.
|
37 | column_definition->auto_flags == Field::NONE) // no function default |
| 4223 | { | ||
| 4224 |
3/8✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 15 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
15 | DBUG_PRINT("info", ("First TIMESTAMP column '%s' was promoted to " |
| 4225 | "DEFAULT CURRENT_TIMESTAMP ON UPDATE " | ||
| 4226 | "CURRENT_TIMESTAMP", | ||
| 4227 | column_definition->field_name)); | ||
| 4228 | 15 | column_definition->auto_flags = | |
| 4229 | Field::DEFAULT_NOW | Field::ON_UPDATE_NOW; | ||
| 4230 | } | ||
| 4231 | 70 | return; | |
| 4232 | } | ||
| 4233 | } | ||
| 4234 | } | ||
| 4235 | |||
| 4236 | /** | ||
| 4237 | Check if there is a duplicate key. Report a warning for every duplicate key. | ||
| 4238 | |||
| 4239 | @param thd Thread context. | ||
| 4240 | @param error_schema_name Schema name of the table used for error reporting. | ||
| 4241 | @param error_table_name Table name used for error reporting. | ||
| 4242 | @param key Key to be checked. | ||
| 4243 | @param key_info Array with all keys for the table. | ||
| 4244 | @param key_count Number of keys in the table. | ||
| 4245 | @param alter_info Alter_info structure describing ALTER TABLE. | ||
| 4246 | |||
| 4247 | @note Unlike has_index_def_changed() and similar code in | ||
| 4248 | mysql_compare_tables() this function compares KEY objects for the same | ||
| 4249 | table/created by the same mysql_prepare_create(). Hence difference in | ||
| 4250 | field number comparison. We also differentiate UNIQUE and PRIMARY keys. | ||
| 4251 | |||
| 4252 | @retval false Ok. | ||
| 4253 | @retval true Error. | ||
| 4254 | */ | ||
| 4255 | 929338 | static bool check_duplicate_key(THD *thd, const char *error_schema_name, | |
| 4256 | const char *error_table_name, const KEY *key, | ||
| 4257 | const KEY *key_info, uint key_count, | ||
| 4258 | Alter_info *alter_info) { | ||
| 4259 | const KEY *k; | ||
| 4260 | 929338 | const KEY *k_end = key_info + key_count; | |
| 4261 | |||
| 4262 | /* This function should not be called for PRIMARY or generated keys. */ | ||
| 4263 |
2/4✓ Branch 0 taken 929338 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 929338 times.
✗ Branch 3 not taken.
|
929338 | assert(key->name != primary_key_name && !(key->flags & HA_GENERATED_KEY)); |
| 4264 | |||
| 4265 |
2/2✓ Branch 0 taken 3167555 times.
✓ Branch 1 taken 103 times.
|
3167658 | for (k = key_info; k != k_end; k++) { |
| 4266 | // Looking for a similar key... | ||
| 4267 | |||
| 4268 |
2/2✓ Branch 0 taken 928962 times.
✓ Branch 1 taken 2238593 times.
|
3167555 | if (k == key) { |
| 4269 | /* | ||
| 4270 | Since the duplicate index might exist before or after | ||
| 4271 | the modified key in the list, we continue the | ||
| 4272 | comparison with rest of the keys in case of DROP COLUMN | ||
| 4273 | operation. | ||
| 4274 | */ | ||
| 4275 |
2/2✓ Branch 0 taken 111 times.
✓ Branch 1 taken 928851 times.
|
928962 | if (alter_info->flags & Alter_info::ALTER_DROP_COLUMN) |
| 4276 | 111 | continue; | |
| 4277 | else | ||
| 4278 | 928851 | break; | |
| 4279 | } | ||
| 4280 | |||
| 4281 | /* | ||
| 4282 | Treat key as not duplicate if: | ||
| 4283 | - it is generated (as it will be automagically removed if duplicate later) | ||
| 4284 | - has different type (Instead of differentiating between PRIMARY and | ||
| 4285 | UNIQUE keys we simply skip check for PRIMARY keys. The fact that we | ||
| 4286 | have only one primary key for the table is checked elsewhere.) | ||
| 4287 | - has different algorithm | ||
| 4288 | - has different number of key parts | ||
| 4289 | */ | ||
| 4290 |
2/2✓ Branch 0 taken 2238152 times.
✓ Branch 1 taken 441 times.
|
2238593 | if ((k->flags & HA_GENERATED_KEY) || |
| 4291 |
2/2✓ Branch 0 taken 1136950 times.
✓ Branch 1 taken 1101202 times.
|
2238152 | ((key->flags & HA_KEYFLAG_MASK) != (k->flags & HA_KEYFLAG_MASK)) || |
| 4292 |
4/4✓ Branch 0 taken 782681 times.
✓ Branch 1 taken 354269 times.
✓ Branch 2 taken 782675 times.
✓ Branch 3 taken 6 times.
|
1136950 | (k->name == primary_key_name) || (key->algorithm != k->algorithm) || |
| 4293 |
2/2✓ Branch 0 taken 167237 times.
✓ Branch 1 taken 615438 times.
|
782675 | (key->user_defined_key_parts != k->user_defined_key_parts)) { |
| 4294 | // Keys are different. | ||
| 4295 | 1623155 | continue; | |
| 4296 | } | ||
| 4297 | |||
| 4298 | /* | ||
| 4299 | Keys 'key' and 'k' might be identical. | ||
| 4300 | Check that the keys have identical columns in the same order. | ||
| 4301 | */ | ||
| 4302 | const KEY_PART_INFO *key_part; | ||
| 4303 | 615438 | const KEY_PART_INFO *key_part_end = | |
| 4304 | 615438 | key->key_part + key->user_defined_key_parts; | |
| 4305 | const KEY_PART_INFO *k_part; | ||
| 4306 | 615438 | bool all_columns_are_identical = true; | |
| 4307 | |||
| 4308 | 615438 | for (key_part = key->key_part, k_part = k->key_part; | |
| 4309 |
2/2✓ Branch 0 taken 629779 times.
✓ Branch 1 taken 384 times.
|
630163 | key_part < key_part_end; key_part++, k_part++) { |
| 4310 | /* | ||
| 4311 | Key definition is different if we are using a different field, | ||
| 4312 | if the used key part length is different or key parts has different | ||
| 4313 | direction. Note since both KEY objects come from | ||
| 4314 | mysql_prepare_create_table() we can compare field numbers directly. | ||
| 4315 | */ | ||
| 4316 |
2/2✓ Branch 0 taken 299504 times.
✓ Branch 1 taken 330275 times.
|
629779 | if ((key_part->length != k_part->length) || |
| 4317 |
2/2✓ Branch 0 taken 14736 times.
✓ Branch 1 taken 284768 times.
|
299504 | (key_part->fieldnr != k_part->fieldnr) || |
| 4318 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 14725 times.
|
14736 | (key_part->key_part_flag != k_part->key_part_flag)) { |
| 4319 | 615054 | all_columns_are_identical = false; | |
| 4320 | 615054 | break; | |
| 4321 | } | ||
| 4322 | } | ||
| 4323 | |||
| 4324 | // Report a warning if we have two identical keys. | ||
| 4325 | |||
| 4326 |
2/2✓ Branch 0 taken 384 times.
✓ Branch 1 taken 615054 times.
|
615438 | if (all_columns_are_identical) { |
| 4327 | 384 | push_warning_printf(thd, Sql_condition::SL_WARNING, ER_DUP_INDEX, | |
| 4328 | 384 | ER_THD(thd, ER_DUP_INDEX), key->name, | |
| 4329 | error_schema_name, error_table_name); | ||
| 4330 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 384 times.
|
384 | if (thd->is_error()) { |
| 4331 | // An error was reported. | ||
| 4332 | ✗ | return true; | |
| 4333 | } | ||
| 4334 | 384 | break; | |
| 4335 | } | ||
| 4336 | } | ||
| 4337 | 929338 | return false; | |
| 4338 | } | ||
| 4339 | |||
| 4340 | /** | ||
| 4341 | Check if there is a collation change from the old field to the new | ||
| 4342 | create field. If so, scan the indexes of the new table (including | ||
| 4343 | the added ones), and check if the field is referred by any index. | ||
| 4344 | |||
| 4345 | @param field Field in old table. | ||
| 4346 | @param new_field Field in new table (create field). | ||
| 4347 | @param ha_alter_info Alter inplace info structure. | ||
| 4348 | |||
| 4349 | @retval true Field changes collation, and is indexed. | ||
| 4350 | @retval false Otherwise. | ||
| 4351 | */ | ||
| 4352 | 458 | static bool is_collation_change_for_indexed_field( | |
| 4353 | const Field &field, const Create_field &new_field, | ||
| 4354 | Alter_inplace_info *ha_alter_info) { | ||
| 4355 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 458 times.
|
458 | assert(new_field.field == &field); |
| 4356 | |||
| 4357 | // No need to check indexes if the collation stays the same. | ||
| 4358 |
2/2✓ Branch 0 taken 64 times.
✓ Branch 1 taken 394 times.
|
458 | if (field.charset() == new_field.charset) return false; |
| 4359 | |||
| 4360 | 394 | const KEY *new_key_end = | |
| 4361 | 394 | ha_alter_info->key_info_buffer + ha_alter_info->key_count; | |
| 4362 | 422 | for (const KEY *new_key = ha_alter_info->key_info_buffer; | |
| 4363 |
2/2✓ Branch 0 taken 356 times.
✓ Branch 1 taken 66 times.
|
422 | new_key < new_key_end; new_key++) { |
| 4364 | /* | ||
| 4365 | If the key of the new table has a part which referring to the create | ||
| 4366 | field submitted, then mark this as a change of the stored column type. | ||
| 4367 | This will prohibit performing this as an inplace operation. | ||
| 4368 | */ | ||
| 4369 | 356 | const KEY_PART_INFO *end = | |
| 4370 | 356 | new_key->key_part + new_key->user_defined_key_parts; | |
| 4371 |
2/2✓ Branch 0 taken 1305 times.
✓ Branch 1 taken 28 times.
|
1333 | for (const KEY_PART_INFO *new_part = new_key->key_part; new_part < end; |
| 4372 | new_part++) { | ||
| 4373 |
2/2✓ Branch 0 taken 328 times.
✓ Branch 1 taken 977 times.
|
1305 | if (get_field_by_index(ha_alter_info->alter_info, new_part->fieldnr) == |
| 4374 | &new_field) | ||
| 4375 | 328 | return true; | |
| 4376 | } | ||
| 4377 | } | ||
| 4378 | |||
| 4379 | 66 | return false; | |
| 4380 | } | ||
| 4381 | |||
| 4382 | /** | ||
| 4383 | Helper function which allows to detect column types for which we historically | ||
| 4384 | used key packing (optimization implemented only by MyISAM) under erroneous | ||
| 4385 | assumption that they have BLOB type. | ||
| 4386 | */ | ||
| 4387 | 16236 | static bool is_phony_blob(enum_field_types sql_type, uint decimals) { | |
| 4388 | 16236 | const uint FIELDFLAG_BLOB = 1024; | |
| 4389 | 16236 | const uint FIELDFLAG_DEC_SHIFT = 8; | |
| 4390 | |||
| 4391 |
3/4✓ Branch 0 taken 16222 times.
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 16222 times.
|
16236 | return (sql_type == MYSQL_TYPE_NEWDECIMAL || sql_type == MYSQL_TYPE_DOUBLE || |
| 4392 |
1/2✓ Branch 0 taken 16236 times.
✗ Branch 1 not taken.
|
32472 | sql_type == MYSQL_TYPE_DECIMAL) && |
| 4393 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
16250 | (((decimals << FIELDFLAG_DEC_SHIFT) & FIELDFLAG_BLOB) != 0); |
| 4394 | } | ||
| 4395 | |||
| 4396 | 53465 | static bool prepare_set_field(THD *thd, Create_field *sql_field) { | |
| 4397 |
1/2✓ Branch 0 taken 53465 times.
✗ Branch 1 not taken.
|
53465 | DBUG_TRACE; |
| 4398 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 53465 times.
|
53465 | assert(sql_field->sql_type == MYSQL_TYPE_SET); |
| 4399 | |||
| 4400 | /* | ||
| 4401 | Create typelib from interval_list, and if necessary | ||
| 4402 | convert strings from client character set to the | ||
| 4403 | column character set. | ||
| 4404 | */ | ||
| 4405 |
2/2✓ Branch 0 taken 45965 times.
✓ Branch 1 taken 7500 times.
|
53465 | if (!sql_field->interval) { |
| 4406 | /* | ||
| 4407 | Create the typelib in runtime memory - we will free the | ||
| 4408 | occupied memory at the same time when we free this | ||
| 4409 | sql_field -- at the end of execution. | ||
| 4410 | */ | ||
| 4411 |
1/2✓ Branch 0 taken 45965 times.
✗ Branch 1 not taken.
|
45965 | sql_field->interval = create_typelib(thd->mem_root, sql_field); |
| 4412 | } | ||
| 4413 | |||
| 4414 | // Comma is an invalid character for SET names | ||
| 4415 | char comma_buf[4]; /* 4 bytes for utf32 */ | ||
| 4416 |
1/2✓ Branch 0 taken 53465 times.
✗ Branch 1 not taken.
|
53465 | int comma_length = sql_field->charset->cset->wc_mb( |
| 4417 | sql_field->charset, ',', reinterpret_cast<uchar *>(comma_buf), | ||
| 4418 | reinterpret_cast<uchar *>(comma_buf) + sizeof(comma_buf)); | ||
| 4419 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 53465 times.
|
53465 | assert(comma_length > 0); |
| 4420 | |||
| 4421 |
2/2✓ Branch 0 taken 1263764 times.
✓ Branch 1 taken 53464 times.
|
1317228 | for (uint i = 0; i < sql_field->interval->count; i++) { |
| 4422 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1263763 times.
|
1263764 | if (sql_field->charset->coll->strstr(sql_field->charset, |
| 4423 | 1263764 | sql_field->interval->type_names[i], | |
| 4424 |
1/2✓ Branch 0 taken 1263764 times.
✗ Branch 1 not taken.
|
1263764 | sql_field->interval->type_lengths[i], |
| 4425 | comma_buf, comma_length, nullptr, 0)) { | ||
| 4426 | 1 | ErrConvString err(sql_field->interval->type_names[i], | |
| 4427 | 1 | sql_field->interval->type_lengths[i], | |
| 4428 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | sql_field->charset); |
| 4429 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_ILLEGAL_VALUE_FOR_TYPE, MYF(0), "set", err.ptr()); |
| 4430 | 1 | return true; | |
| 4431 | } | ||
| 4432 | } | ||
| 4433 | |||
| 4434 |
2/2✓ Branch 0 taken 8259 times.
✓ Branch 1 taken 45205 times.
|
53464 | if (sql_field->constant_default != nullptr) { |
| 4435 | const char *not_used; | ||
| 4436 | uint not_used2; | ||
| 4437 | 8259 | bool not_found = false; | |
| 4438 | 8259 | String str; | |
| 4439 |
1/2✓ Branch 0 taken 8259 times.
✗ Branch 1 not taken.
|
8259 | String *def = sql_field->constant_default->val_str(&str); |
| 4440 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 8256 times.
|
8259 | if (def == nullptr) /* SQL "NULL" maps to NULL */ |
| 4441 | { | ||
| 4442 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
|
3 | if ((sql_field->flags & NOT_NULL_FLAG) != 0) { |
| 4443 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name); |
| 4444 | 1 | return true; | |
| 4445 | } | ||
| 4446 | |||
| 4447 | /* else, NULL is an allowed value */ | ||
| 4448 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | (void)find_set(sql_field->interval, nullptr, 0, sql_field->charset, |
| 4449 | ¬_used, ¬_used2, ¬_found); | ||
| 4450 | } else /* not NULL */ | ||
| 4451 | { | ||
| 4452 |
1/2✓ Branch 0 taken 8256 times.
✗ Branch 1 not taken.
|
8256 | (void)find_set(sql_field->interval, def->ptr(), def->length(), |
| 4453 | sql_field->charset, ¬_used, ¬_used2, ¬_found); | ||
| 4454 | } | ||
| 4455 | |||
| 4456 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 8251 times.
|
8258 | if (not_found) { |
| 4457 |
1/2✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 | my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name); |
| 4458 | 7 | return true; | |
| 4459 | } | ||
| 4460 |
2/2✓ Branch 0 taken 8251 times.
✓ Branch 1 taken 8 times.
|
8259 | } |
| 4461 | |||
| 4462 | 53456 | return false; | |
| 4463 | 53465 | } | |
| 4464 | |||
| 4465 | 848359 | static bool prepare_enum_field(THD *thd, Create_field *sql_field) { | |
| 4466 |
1/2✓ Branch 0 taken 848359 times.
✗ Branch 1 not taken.
|
848359 | DBUG_TRACE; |
| 4467 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 848359 times.
|
848359 | assert(sql_field->sql_type == MYSQL_TYPE_ENUM); |
| 4468 | |||
| 4469 | /* | ||
| 4470 | Create typelib from interval_list, and if necessary | ||
| 4471 | convert strings from client character set to the | ||
| 4472 | column character set. | ||
| 4473 | */ | ||
| 4474 |
2/2✓ Branch 0 taken 500906 times.
✓ Branch 1 taken 347453 times.
|
848359 | if (!sql_field->interval) { |
| 4475 | /* | ||
| 4476 | Create the typelib in runtime memory - we will free the | ||
| 4477 | occupied memory at the same time when we free this | ||
| 4478 | sql_field -- at the end of execution. | ||
| 4479 | */ | ||
| 4480 |
1/2✓ Branch 0 taken 500906 times.
✗ Branch 1 not taken.
|
500906 | sql_field->interval = create_typelib(thd->mem_root, sql_field); |
| 4481 | } | ||
| 4482 | |||
| 4483 |
2/2✓ Branch 0 taken 369837 times.
✓ Branch 1 taken 478522 times.
|
848359 | if (sql_field->constant_default != nullptr) { |
| 4484 | 369837 | String str; | |
| 4485 |
1/2✓ Branch 0 taken 369837 times.
✗ Branch 1 not taken.
|
369837 | String *def = sql_field->constant_default->val_str(&str); |
| 4486 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 369834 times.
|
369837 | if (def == nullptr) /* SQL "NULL" maps to NULL */ |
| 4487 | { | ||
| 4488 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
|
3 | if ((sql_field->flags & NOT_NULL_FLAG) != 0) { |
| 4489 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name); |
| 4490 | 1 | return true; | |
| 4491 | } | ||
| 4492 | |||
| 4493 | /* else, the defaults yield the correct length for NULLs. */ | ||
| 4494 | } else /* not NULL */ | ||
| 4495 | { | ||
| 4496 |
1/2✓ Branch 0 taken 369834 times.
✗ Branch 1 not taken.
|
739668 | def->length(sql_field->charset->cset->lengthsp( |
| 4497 | 369834 | sql_field->charset, def->ptr(), def->length())); | |
| 4498 |
1/2✓ Branch 0 taken 369834 times.
✗ Branch 1 not taken.
|
369834 | if (find_type2(sql_field->interval, def->ptr(), def->length(), |
| 4499 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 369828 times.
|
369834 | sql_field->charset) == 0) /* not found */ |
| 4500 | { | ||
| 4501 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name); |
| 4502 | 6 | return true; | |
| 4503 | } | ||
| 4504 | } | ||
| 4505 |
2/2✓ Branch 0 taken 369830 times.
✓ Branch 1 taken 7 times.
|
369837 | } |
| 4506 | |||
| 4507 | 848352 | return false; | |
| 4508 | 848359 | } | |
| 4509 | |||
| 4510 | 6385553 | bool prepare_create_field(THD *thd, const char *error_schema_name, | |
| 4511 | const char *error_table_name, | ||
| 4512 | HA_CREATE_INFO *create_info, | ||
| 4513 | List<Create_field> *create_list, | ||
| 4514 | int *select_field_pos, handler *file, | ||
| 4515 | Create_field *sql_field, int field_no) { | ||
| 4516 |
1/2✓ Branch 0 taken 6385562 times.
✗ Branch 1 not taken.
|
6385553 | DBUG_TRACE; |
| 4517 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6385562 times.
|
6385562 | assert(create_list); |
| 4518 | const CHARSET_INFO *save_cs; | ||
| 4519 | |||
| 4520 | /* Set field charset. */ | ||
| 4521 |
1/2✓ Branch 0 taken 6385558 times.
✗ Branch 1 not taken.
|
6385562 | save_cs = sql_field->charset = get_sql_field_charset(sql_field, create_info); |
| 4522 | |||
| 4523 |
2/2✓ Branch 0 taken 6853 times.
✓ Branch 1 taken 6378705 times.
|
6385558 | if (sql_field->flags & BINCMP_FLAG) { |
| 4524 | // e.g. CREATE TABLE t1 (a CHAR(1) BINARY); | ||
| 4525 |
2/4✓ Branch 0 taken 6853 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6853 times.
|
6853 | if (!(sql_field->charset = get_charset_by_csname(sql_field->charset->csname, |
| 4526 | MY_CS_BINSORT, MYF(0)))) { | ||
| 4527 | char tmp[65]; | ||
| 4528 | ✗ | strmake(strmake(tmp, save_cs->csname, sizeof(tmp) - 4), | |
| 4529 | STRING_WITH_LEN("_bin")); | ||
| 4530 | ✗ | my_error(ER_UNKNOWN_COLLATION, MYF(0), tmp); | |
| 4531 | ✗ | return true; | |
| 4532 | } | ||
| 4533 | /* | ||
| 4534 | Now that we have sql_field->charset set properly, | ||
| 4535 | we don't need the BINCMP_FLAG any longer. | ||
| 4536 | */ | ||
| 4537 | 6853 | sql_field->flags &= ~BINCMP_FLAG; | |
| 4538 | } | ||
| 4539 | |||
| 4540 | /* | ||
| 4541 | Convert the default value from client character | ||
| 4542 | set into the column character set if necessary. | ||
| 4543 | */ | ||
| 4544 |
2/2✓ Branch 0 taken 582199 times.
✓ Branch 1 taken 5803359 times.
|
6385558 | if (sql_field->constant_default && |
| 4545 |
2/2✓ Branch 0 taken 108424 times.
✓ Branch 1 taken 473775 times.
|
582199 | save_cs != sql_field->constant_default->collation.collation && |
| 4546 |
1/2✓ Branch 0 taken 108424 times.
✗ Branch 1 not taken.
|
108424 | (sql_field->sql_type == MYSQL_TYPE_VAR_STRING || |
| 4547 |
2/2✓ Branch 0 taken 83572 times.
✓ Branch 1 taken 24852 times.
|
108424 | sql_field->sql_type == MYSQL_TYPE_STRING || |
| 4548 |
2/2✓ Branch 0 taken 81102 times.
✓ Branch 1 taken 2470 times.
|
83572 | sql_field->sql_type == MYSQL_TYPE_SET || |
| 4549 |
2/2✓ Branch 0 taken 39026 times.
✓ Branch 1 taken 42076 times.
|
81102 | sql_field->sql_type == MYSQL_TYPE_ENUM)) { |
| 4550 | /* | ||
| 4551 | Starting from 5.1 we work here with a copy of Create_field | ||
| 4552 | created by the caller, not with the instance that was | ||
| 4553 | originally created during parsing. It's OK to create | ||
| 4554 | a temporary item and initialize with it a member of the | ||
| 4555 | copy -- this item will be thrown away along with the copy | ||
| 4556 | at the end of execution, and thus not introduce a dangling | ||
| 4557 | pointer in the parsed tree of a prepared statement or a | ||
| 4558 | stored procedure statement. | ||
| 4559 | */ | ||
| 4560 | 66346 | sql_field->constant_default = | |
| 4561 |
1/2✓ Branch 0 taken 66346 times.
✗ Branch 1 not taken.
|
66348 | sql_field->constant_default->safe_charset_converter(thd, save_cs); |
| 4562 | |||
| 4563 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 66345 times.
|
66346 | if (sql_field->constant_default == nullptr) { |
| 4564 | /* Could not convert */ | ||
| 4565 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name); |
| 4566 | 1 | return true; | |
| 4567 | } | ||
| 4568 | } | ||
| 4569 | |||
| 4570 |
2/2✓ Branch 0 taken 52848 times.
✓ Branch 1 taken 6332707 times.
|
6385555 | if (sql_field->sql_type == MYSQL_TYPE_SET) { |
| 4571 |
3/4✓ Branch 0 taken 52848 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 52839 times.
|
52848 | if (prepare_set_field(thd, sql_field)) return true; |
| 4572 |
2/2✓ Branch 0 taken 835734 times.
✓ Branch 1 taken 5496973 times.
|
6332707 | } else if (sql_field->sql_type == MYSQL_TYPE_ENUM) { |
| 4573 |
3/4✓ Branch 0 taken 835734 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 835727 times.
|
835734 | if (prepare_enum_field(thd, sql_field)) return true; |
| 4574 |
2/2✓ Branch 0 taken 2554 times.
✓ Branch 1 taken 5494419 times.
|
5496973 | } else if (sql_field->sql_type == MYSQL_TYPE_BIT) { |
| 4575 |
2/2✓ Branch 0 taken 246 times.
✓ Branch 1 taken 2308 times.
|
2554 | if (file->ha_table_flags() & HA_CAN_BIT_FIELD) { |
| 4576 | 246 | create_info->null_bits += | |
| 4577 |
1/2✓ Branch 0 taken 246 times.
✗ Branch 1 not taken.
|
246 | sql_field->max_display_width_in_codepoints() & 7; |
| 4578 | 246 | sql_field->treat_bit_as_char = false; | |
| 4579 | } else | ||
| 4580 | 2308 | sql_field->treat_bit_as_char = true; | |
| 4581 | } | ||
| 4582 | |||
| 4583 | 6385539 | bool convert_to_character_set = | |
| 4584 | 6385539 | (create_info->used_fields & HA_CREATE_USED_CHARSET); | |
| 4585 |
3/4✓ Branch 0 taken 6385540 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 6385531 times.
|
6385539 | if (prepare_blob_field(thd, sql_field, convert_to_character_set)) { |
| 4586 | 9 | return true; | |
| 4587 | } | ||
| 4588 | |||
| 4589 |
2/2✓ Branch 0 taken 2284990 times.
✓ Branch 1 taken 4100541 times.
|
6385531 | if (!(sql_field->flags & NOT_NULL_FLAG)) create_info->null_bits++; |
| 4590 | |||
| 4591 |
3/4✓ Branch 0 taken 6385534 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 6385531 times.
|
6385531 | if (check_column_name(sql_field->field_name)) { |
| 4592 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | my_error(ER_WRONG_COLUMN_NAME, MYF(0), sql_field->field_name); |
| 4593 | 3 | return true; | |
| 4594 | } | ||
| 4595 | |||
| 4596 | // Validate field comment string | ||
| 4597 | 6385531 | std::string invalid_sub_str; | |
| 4598 | 12771050 | if (is_invalid_string( | |
| 4599 |
3/4✓ Branch 0 taken 6385519 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 6385517 times.
|
6385531 | LEX_CSTRING{sql_field->comment.str, sql_field->comment.length}, |
| 4600 | system_charset_info, invalid_sub_str)) { | ||
| 4601 | // Provide contextual information | ||
| 4602 |
3/6✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
4 | std::string qualified_field_name = std::string(error_schema_name) + "." + |
| 4603 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
8 | std::string(error_table_name) + "." + |
| 4604 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
6 | std::string(sql_field->field_name); |
| 4605 | |||
| 4606 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | my_error(ER_COMMENT_CONTAINS_INVALID_STRING, MYF(0), "field", |
| 4607 | qualified_field_name.c_str(), system_charset_info->csname, | ||
| 4608 | invalid_sub_str.c_str()); | ||
| 4609 | 2 | return true; | |
| 4610 | 2 | } | |
| 4611 | |||
| 4612 |
3/4✓ Branch 0 taken 6385530 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 6385523 times.
|
6385517 | if (validate_comment_length(thd, sql_field->comment.str, |
| 4613 | &sql_field->comment.length, COLUMN_COMMENT_MAXLEN, | ||
| 4614 | ER_TOO_LONG_FIELD_COMMENT, sql_field->field_name)) | ||
| 4615 | 7 | return true; | |
| 4616 | |||
| 4617 | // If this column has an SRID specified, check if the SRID actually exists | ||
| 4618 | // in the data dictionary. | ||
| 4619 |
7/8✓ Branch 0 taken 1636 times.
✓ Branch 1 taken 6383888 times.
✓ Branch 2 taken 1636 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 187 times.
✓ Branch 5 taken 1449 times.
✓ Branch 6 taken 187 times.
✓ Branch 7 taken 6385337 times.
|
6385523 | if (sql_field->m_srid.has_value() && sql_field->m_srid.value() != 0) { |
| 4620 | 187 | bool exists = false; | |
| 4621 |
3/6✓ Branch 0 taken 187 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 187 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 187 times.
|
187 | if (Srs_fetcher::srs_exists(thd, sql_field->m_srid.value(), &exists)) { |
| 4622 | // An error has already been raised | ||
| 4623 | 4 | return true; /* purecov: deadcode */ | |
| 4624 | } | ||
| 4625 | |||
| 4626 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 183 times.
|
187 | if (!exists) { |
| 4627 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | my_error(ER_SRS_NOT_FOUND, MYF(0), sql_field->m_srid.value()); |
| 4628 | 4 | return true; | |
| 4629 | } | ||
| 4630 | } | ||
| 4631 | |||
| 4632 | /* Check if we have used the same field name before */ | ||
| 4633 | Create_field *dup_field; | ||
| 4634 |
1/2✓ Branch 0 taken 6385519 times.
✗ Branch 1 not taken.
|
6385520 | List_iterator<Create_field> it(*create_list); |
| 4635 |
2/2✓ Branch 0 taken 105064709 times.
✓ Branch 1 taken 6376618 times.
|
111441340 | for (int dup_no = 0; (dup_field = it++) != sql_field; dup_no++) { |
| 4636 |
1/2✓ Branch 0 taken 105064709 times.
✗ Branch 1 not taken.
|
105064709 | if (my_strcasecmp(system_charset_info, sql_field->field_name, |
| 4637 |
2/2✓ Branch 0 taken 8889 times.
✓ Branch 1 taken 105055820 times.
|
105064709 | dup_field->field_name) == 0) { |
| 4638 | /* | ||
| 4639 | If this was a CREATE ... SELECT statement, accept a field | ||
| 4640 | redefinition if we are changing a field in the SELECT part | ||
| 4641 | */ | ||
| 4642 |
4/4✓ Branch 0 taken 1539 times.
✓ Branch 1 taken 7350 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 1535 times.
|
8889 | if (field_no < (*select_field_pos) || dup_no >= (*select_field_pos)) { |
| 4643 | // If one of the columns is a functional index column, but not both, | ||
| 4644 | // return an error saying that the column name is in use. The reason we | ||
| 4645 | // only raise an error if one, but not both, is a functional index | ||
| 4646 | // column, is that we want to report a "duplicate key name"-error if the | ||
| 4647 | // user renames a functional index to an existing functional index name: | ||
| 4648 | // | ||
| 4649 | // CREATE TABLE t1 ( | ||
| 4650 | // col1 INT | ||
| 4651 | // , INDEX idx ((col1 + 1)) | ||
| 4652 | // , INDEX idx2 ((col1 + 2))); | ||
| 4653 | // | ||
| 4654 | // ALTER TABLE t1 RENAME INDEX idx TO idx2; | ||
| 4655 | // | ||
| 4656 | // Note that duplicate names for regular indexes are detected later, so | ||
| 4657 | // we don't bother checking those here. | ||
| 4658 |
1/2✓ Branch 0 taken 7354 times.
✗ Branch 1 not taken.
|
7354 | if ((is_field_for_functional_index(dup_field) != |
| 4659 |
3/4✓ Branch 0 taken 7354 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 7352 times.
|
7354 | is_field_for_functional_index(sql_field))) { |
| 4660 | 2 | std::string error_description; | |
| 4661 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | error_description.append("The column name '"); |
| 4662 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | error_description.append(sql_field->field_name); |
| 4663 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | error_description.append("' is already in use by a hidden column"); |
| 4664 | |||
| 4665 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | my_error(ER_INTERNAL_ERROR, MYF(0), error_description.c_str()); |
| 4666 | 2 | return true; | |
| 4667 | 2 | } | |
| 4668 | |||
| 4669 |
5/6✓ Branch 0 taken 7352 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7351 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 7351 times.
✓ Branch 5 taken 1 times.
|
14703 | if (!is_field_for_functional_index(dup_field) && |
| 4670 |
2/4✓ Branch 0 taken 7351 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7351 times.
✗ Branch 3 not taken.
|
7351 | !is_field_for_functional_index(sql_field)) { |
| 4671 |
1/2✓ Branch 0 taken 7351 times.
✗ Branch 1 not taken.
|
7351 | my_error(ER_DUP_FIELDNAME, MYF(0), sql_field->field_name); |
| 4672 | 7351 | return true; | |
| 4673 | } | ||
| 4674 | 1 | } else { | |
| 4675 | /* Field redefined */ | ||
| 4676 | |||
| 4677 | /* | ||
| 4678 | If we are replacing a BIT field, revert the increment | ||
| 4679 | of null_bits that was done above. | ||
| 4680 | */ | ||
| 4681 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 1535 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1535 times.
|
1535 | if (sql_field->sql_type == MYSQL_TYPE_BIT && |
| 4682 | ✗ | file->ha_table_flags() & HA_CAN_BIT_FIELD) { | |
| 4683 | ✗ | create_info->null_bits -= | |
| 4684 | ✗ | sql_field->max_display_width_in_codepoints() & 7; | |
| 4685 | } | ||
| 4686 | |||
| 4687 | 1535 | sql_field->constant_default = dup_field->constant_default; | |
| 4688 | 1535 | sql_field->sql_type = dup_field->sql_type; | |
| 4689 | |||
| 4690 | /* | ||
| 4691 | If we are replacing a field with a BIT field, we need | ||
| 4692 | to initialize treat_bit_as_char. Note that we do not need to | ||
| 4693 | increment null_bits here as this dup_field | ||
| 4694 | has already been processed. | ||
| 4695 | */ | ||
| 4696 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1534 times.
|
1535 | if (sql_field->sql_type == MYSQL_TYPE_BIT) { |
| 4697 | 1 | sql_field->treat_bit_as_char = | |
| 4698 | 1 | !(file->ha_table_flags() & HA_CAN_BIT_FIELD); | |
| 4699 | } | ||
| 4700 | |||
| 4701 | 1535 | sql_field->charset = | |
| 4702 |
1/2✓ Branch 0 taken 1535 times.
✗ Branch 1 not taken.
|
1535 | (dup_field->charset ? dup_field->charset |
| 4703 | : create_info->default_table_charset); | ||
| 4704 |
1/2✓ Branch 0 taken 1535 times.
✗ Branch 1 not taken.
|
1535 | sql_field->set_max_display_width_from_create_field(*dup_field); |
| 4705 | 1535 | sql_field->decimals = dup_field->decimals; | |
| 4706 | 1535 | sql_field->auto_flags = dup_field->auto_flags; | |
| 4707 | /* | ||
| 4708 | We're making one field from two, the result field will have | ||
| 4709 | dup_field->flags as flags. If we've incremented null_bits | ||
| 4710 | because of sql_field->flags, decrement it back. | ||
| 4711 | */ | ||
| 4712 |
2/2✓ Branch 0 taken 1193 times.
✓ Branch 1 taken 342 times.
|
1535 | if (!(sql_field->flags & NOT_NULL_FLAG)) create_info->null_bits--; |
| 4713 | |||
| 4714 | 1535 | sql_field->flags = dup_field->flags; | |
| 4715 | 1535 | sql_field->interval = dup_field->interval; | |
| 4716 | 1535 | sql_field->gcol_info = dup_field->gcol_info; | |
| 4717 | 1535 | sql_field->m_default_val_expr = dup_field->m_default_val_expr; | |
| 4718 | 1535 | sql_field->stored_in_db = dup_field->stored_in_db; | |
| 4719 | 1535 | sql_field->hidden = dup_field->hidden; | |
| 4720 |
1/2✓ Branch 0 taken 1535 times.
✗ Branch 1 not taken.
|
1535 | it.remove(); // Remove first (create) definition |
| 4721 | 1535 | (*select_field_pos)--; | |
| 4722 | 1535 | break; | |
| 4723 | } | ||
| 4724 | } | ||
| 4725 | } | ||
| 4726 | |||
| 4727 | /* Don't pack rows in old tables if the user has requested this */ | ||
| 4728 |
2/2✓ Branch 0 taken 5478421 times.
✓ Branch 1 taken 899732 times.
|
6378153 | if ((sql_field->flags & BLOB_FLAG) || |
| 4729 |
2/2✓ Branch 0 taken 1171400 times.
✓ Branch 1 taken 4307021 times.
|
5478421 | (sql_field->sql_type == MYSQL_TYPE_VARCHAR && |
| 4730 |
2/2✓ Branch 0 taken 1171393 times.
✓ Branch 1 taken 7 times.
|
1171400 | create_info->row_type != ROW_TYPE_FIXED)) |
| 4731 | 2071125 | create_info->table_options |= HA_OPTION_PACK_RECORD; | |
| 4732 | |||
| 4733 |
3/4✓ Branch 0 taken 6378167 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 6378150 times.
|
6378153 | if (prepare_pack_create_field(thd, sql_field, file->ha_table_flags())) |
| 4734 | 17 | return true; | |
| 4735 | |||
| 4736 | 6378150 | return false; | |
| 4737 | 6385562 | } | |
| 4738 | |||
| 4739 | 749478 | static void calculate_field_offsets(List<Create_field> *create_list) { | |
| 4740 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 749478 times.
|
749478 | assert(create_list); |
| 4741 |
1/2✓ Branch 0 taken 749487 times.
✗ Branch 1 not taken.
|
749478 | List_iterator<Create_field> it(*create_list); |
| 4742 | 749487 | size_t record_offset = 0; | |
| 4743 | 749487 | bool has_vgc = false; | |
| 4744 | Create_field *sql_field; | ||
| 4745 |
2/2✓ Branch 0 taken 6142805 times.
✓ Branch 1 taken 749488 times.
|
6892279 | while ((sql_field = it++)) { |
| 4746 | 6142805 | sql_field->offset = record_offset; | |
| 4747 | /* | ||
| 4748 | For now skip fields that are not physically stored in the database | ||
| 4749 | (generated fields) and update their offset later (see the next loop). | ||
| 4750 | */ | ||
| 4751 |
2/2✓ Branch 0 taken 6132410 times.
✓ Branch 1 taken 10395 times.
|
6142805 | if (sql_field->stored_in_db) |
| 4752 |
1/2✓ Branch 0 taken 6132397 times.
✗ Branch 1 not taken.
|
6132410 | record_offset += sql_field->pack_length(); |
| 4753 | else | ||
| 4754 | 10395 | has_vgc = true; | |
| 4755 | } | ||
| 4756 | /* Update generated fields' offset*/ | ||
| 4757 |
2/2✓ Branch 0 taken 5932 times.
✓ Branch 1 taken 743556 times.
|
749488 | if (has_vgc) { |
| 4758 | 5932 | it.rewind(); | |
| 4759 |
2/2✓ Branch 0 taken 31554 times.
✓ Branch 1 taken 5932 times.
|
37486 | while ((sql_field = it++)) { |
| 4760 |
2/2✓ Branch 0 taken 10395 times.
✓ Branch 1 taken 21159 times.
|
31554 | if (!sql_field->stored_in_db) { |
| 4761 | 10395 | sql_field->offset = record_offset; | |
| 4762 |
1/2✓ Branch 0 taken 10395 times.
✗ Branch 1 not taken.
|
10395 | record_offset += sql_field->pack_length(); |
| 4763 | } | ||
| 4764 | } | ||
| 4765 | } | ||
| 4766 | 749488 | } | |
| 4767 | |||
| 4768 | /** | ||
| 4769 | Count keys and key segments. Note that FKs are ignored. | ||
| 4770 | Also mark redundant keys to be ignored. | ||
| 4771 | |||
| 4772 | @param[in,out] key_list List of keys to count and possibly mark as ignored. | ||
| 4773 | @param[out] key_count Returned number of keys counted (excluding FK). | ||
| 4774 | @param[out] key_parts Returned number of key segments (excluding FK). | ||
| 4775 | @param[out] fk_key_count Returned number of foreign keys. | ||
| 4776 | @param[in,out] redundant_keys Array where keys to be ignored will be marked. | ||
| 4777 | @param[in] se_index_flags Storage's flags for index support | ||
| 4778 | */ | ||
| 4779 | |||
| 4780 | 749475 | static bool count_keys(const Mem_root_array<Key_spec *> &key_list, | |
| 4781 | uint *key_count, uint *key_parts, uint *fk_key_count, | ||
| 4782 | Mem_root_array<bool> *redundant_keys, | ||
| 4783 | handler::Table_flags se_index_flags) { | ||
| 4784 | 749475 | *key_count = 0; | |
| 4785 | 749475 | *key_parts = 0; | |
| 4786 | |||
| 4787 |
2/2✓ Branch 0 taken 2691232 times.
✓ Branch 1 taken 749466 times.
|
3440699 | for (size_t key_counter = 0; key_counter < key_list.size(); key_counter++) { |
| 4788 | 2691232 | const Key_spec *key = key_list[key_counter]; | |
| 4789 | |||
| 4790 | 10533845 | for (size_t key2_counter = 0; | |
| 4791 |
5/6✓ Branch 0 taken 10533845 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8454306 times.
✓ Branch 3 taken 2079539 times.
✓ Branch 4 taken 8454306 times.
✓ Branch 5 taken 2079539 times.
|
10533845 | key2_counter < key_list.size() && key_list[key2_counter] != key; |
| 4792 | key2_counter++) { | ||
| 4793 | 8454306 | const Key_spec *key2 = key_list[key2_counter]; | |
| 4794 | /* | ||
| 4795 | foreign_key_prefix(key, key2) returns 0 if key or key2, or both, is | ||
| 4796 | 'generated', and a generated key is a prefix of the other key. | ||
| 4797 | Then we do not need the generated shorter key. | ||
| 4798 | |||
| 4799 | KEYTYPE_SPATIAL and KEYTYPE_FULLTEXT cannot be used as | ||
| 4800 | supporting keys for foreign key constraints even if the | ||
| 4801 | generated key is prefix of such a key. | ||
| 4802 | */ | ||
| 4803 |
2/2✓ Branch 0 taken 4232019 times.
✓ Branch 1 taken 3608779 times.
|
7840798 | if ((key2->type != KEYTYPE_FOREIGN && key->type != KEYTYPE_FOREIGN && |
| 4804 |
4/4✓ Branch 0 taken 4231881 times.
✓ Branch 1 taken 138 times.
✓ Branch 2 taken 4227141 times.
✓ Branch 3 taken 4740 times.
|
4232019 | key2->type != KEYTYPE_SPATIAL && key2->type != KEYTYPE_FULLTEXT && |
| 4805 |
6/6✓ Branch 0 taken 7840798 times.
✓ Branch 1 taken 613508 times.
✓ Branch 2 taken 4227121 times.
✓ Branch 3 taken 20 times.
✓ Branch 4 taken 611693 times.
✓ Branch 5 taken 7842613 times.
|
20522225 | !redundant_keys->at(key2_counter) && |
| 4806 |
2/2✓ Branch 0 taken 611693 times.
✓ Branch 1 taken 3615428 times.
|
4227121 | !foreign_key_prefix(key, key2))) { |
| 4807 | /* TODO: issue warning message */ | ||
| 4808 | /* mark that the generated key should be ignored */ | ||
| 4809 |
4/4✓ Branch 0 taken 38 times.
✓ Branch 1 taken 611655 times.
✓ Branch 2 taken 611655 times.
✓ Branch 3 taken 38 times.
|
611731 | if (!key2->generated || |
| 4810 |
3/4✓ Branch 0 taken 18 times.
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
|
38 | (key->generated && key->columns.size() < key2->columns.size())) |
| 4811 | 611655 | (*redundant_keys)[key_counter] = true; | |
| 4812 | else { | ||
| 4813 | 38 | (*redundant_keys)[key2_counter] = true; | |
| 4814 | 38 | (*key_parts) -= key2->columns.size(); | |
| 4815 | 38 | (*key_count)--; | |
| 4816 | } | ||
| 4817 | 611693 | break; | |
| 4818 | } | ||
| 4819 | } | ||
| 4820 | |||
| 4821 |
2/2✓ Branch 0 taken 2079577 times.
✓ Branch 1 taken 611655 times.
|
2691232 | if (!redundant_keys->at(key_counter)) { |
| 4822 |
2/2✓ Branch 0 taken 612882 times.
✓ Branch 1 taken 1466695 times.
|
2079577 | if (key->type == KEYTYPE_FOREIGN) |
| 4823 | 612882 | (*fk_key_count)++; | |
| 4824 | else { | ||
| 4825 | 1466695 | uint mv_key_parts = 0; | |
| 4826 | 1466695 | (*key_count)++; | |
| 4827 | 1466695 | (*key_parts) += key->columns.size(); | |
| 4828 |
2/2✓ Branch 0 taken 2334559 times.
✓ Branch 1 taken 1466687 times.
|
3801246 | for (uint i = 0; i < key->columns.size(); i++) { |
| 4829 | 2334559 | const Key_part_spec *kp = key->columns[i]; | |
| 4830 |
6/6✓ Branch 0 taken 911 times.
✓ Branch 1 taken 2333648 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 907 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 2334555 times.
|
2334559 | if (!kp->is_ascending() && !(se_index_flags & HA_DESCENDING_INDEX)) { |
| 4831 | 4 | my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "descending indexes"); | |
| 4832 | 4 | return true; | |
| 4833 | } | ||
| 4834 |
6/6✓ Branch 0 taken 860 times.
✓ Branch 1 taken 2333695 times.
✓ Branch 2 taken 423 times.
✓ Branch 3 taken 437 times.
✓ Branch 4 taken 423 times.
✓ Branch 5 taken 2334132 times.
|
2334555 | if (kp->has_expression() && kp->get_expression()->returns_array()) { |
| 4835 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 421 times.
|
423 | if (mv_key_parts++) { |
| 4836 | 2 | my_error(ER_NOT_SUPPORTED_YET, MYF(0), | |
| 4837 | "more than one multi-valued key part per index"); | ||
| 4838 | 2 | return true; | |
| 4839 | } | ||
| 4840 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 420 times.
|
421 | if (!(se_index_flags & HA_MULTI_VALUED_KEY_SUPPORT)) { |
| 4841 | 1 | my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), | |
| 4842 | "multi-valued indexes"); | ||
| 4843 | 1 | return true; | |
| 4844 | } | ||
| 4845 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 419 times.
|
420 | if (kp->is_explicit()) { |
| 4846 | 1 | my_error(ER_WRONG_USAGE, MYF(0), "multi-valued index", | |
| 4847 | "explicit index order"); | ||
| 4848 | 1 | return true; | |
| 4849 | } | ||
| 4850 | } | ||
| 4851 | } | ||
| 4852 | } | ||
| 4853 | } | ||
| 4854 | } | ||
| 4855 | 749466 | return false; | |
| 4856 | } | ||
| 4857 | |||
| 4858 | 2332319 | static bool prepare_key_column(THD *thd, HA_CREATE_INFO *create_info, | |
| 4859 | List<Create_field> *create_list, | ||
| 4860 | const Key_spec *key, const Key_part_spec *column, | ||
| 4861 | const size_t column_nr, KEY *key_info, | ||
| 4862 | KEY_PART_INFO *key_part_info, | ||
| 4863 | const handler *file, int *auto_increment, | ||
| 4864 | const CHARSET_INFO **ft_key_charset) { | ||
| 4865 |
1/2✓ Branch 0 taken 2332320 times.
✗ Branch 1 not taken.
|
2332319 | DBUG_TRACE; |
| 4866 | |||
| 4867 | /* | ||
| 4868 | Find the matching table column. | ||
| 4869 | */ | ||
| 4870 | 2332320 | uint field = 0; | |
| 4871 | 2332320 | Create_field *sql_field = nullptr; | |
| 4872 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2332320 times.
|
2332320 | assert(create_list); |
| 4873 |
5/8✓ Branch 0 taken 2332320 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2332320 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11422454 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 11422445 times.
✓ Branch 7 taken 9 times.
|
11422455 | for (Create_field &it : *create_list) { |
| 4874 |
7/8✓ Branch 0 taken 11417290 times.
✓ Branch 1 taken 5155 times.
✓ Branch 2 taken 11417290 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11417289 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 2332311 times.
✓ Branch 7 taken 9090135 times.
|
22844890 | if ((column->has_expression() || !is_hidden_by_system(&it)) && |
| 4875 |
3/4✓ Branch 0 taken 11422445 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2332311 times.
✓ Branch 3 taken 9090134 times.
|
11422444 | my_strcasecmp(system_charset_info, column->get_field_name(), |
| 4876 | it.field_name) == 0) { | ||
| 4877 | 2332311 | sql_field = ⁢ | |
| 4878 | 2332311 | break; | |
| 4879 | } | ||
| 4880 | 9090135 | field++; | |
| 4881 | } | ||
| 4882 | |||
| 4883 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 2332311 times.
|
2332320 | if (sql_field == nullptr) { |
| 4884 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
9 | my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->get_field_name()); |
| 4885 | 9 | return true; | |
| 4886 | } | ||
| 4887 | |||
| 4888 | Functional_index_error_handler functional_index_error_handler( | ||
| 4889 |
2/4✓ Branch 0 taken 2332311 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2332311 times.
✗ Branch 3 not taken.
|
4664622 | sql_field, {key->name.str, key->name.length}, thd); |
| 4890 | |||
| 4891 | /* | ||
| 4892 | Virtual generated column checks. | ||
| 4893 | */ | ||
| 4894 |
2/2✓ Branch 0 taken 5308 times.
✓ Branch 1 taken 2327002 times.
|
2332310 | if (sql_field->is_virtual_gcol()) { |
| 4895 | 5308 | const char *errmsg = nullptr; | |
| 4896 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 5305 times.
|
5308 | if (key->type == KEYTYPE_FULLTEXT) { |
| 4897 | 3 | errmsg = "Fulltext index on virtual generated column"; | |
| 4898 | 3 | functional_index_error_handler.force_error_code( | |
| 4899 | ER_FULLTEXT_FUNCTIONAL_INDEX); | ||
| 4900 |
2/2✓ Branch 0 taken 5302 times.
✓ Branch 1 taken 3 times.
|
5305 | } else if (key->type == KEYTYPE_SPATIAL || |
| 4901 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5292 times.
|
5302 | sql_field->sql_type == MYSQL_TYPE_GEOMETRY) { |
| 4902 | 13 | errmsg = "Spatial index on virtual generated column"; | |
| 4903 | 13 | functional_index_error_handler.force_error_code( | |
| 4904 | ER_SPATIAL_FUNCTIONAL_INDEX); | ||
| 4905 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5292 times.
|
5292 | } else if (key->type == KEYTYPE_PRIMARY) { |
| 4906 | ✗ | errmsg = "Defining a virtual generated column as primary key"; | |
| 4907 | ✗ | functional_index_error_handler.force_error_code( | |
| 4908 | ER_FUNCTIONAL_INDEX_PRIMARY_KEY); | ||
| 4909 | } | ||
| 4910 | |||
| 4911 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 5292 times.
|
5308 | if (errmsg) { |
| 4912 |
1/2✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
|
16 | my_error(ER_UNSUPPORTED_ACTION_ON_GENERATED_COLUMN, MYF(0), errmsg); |
| 4913 | 16 | return true; | |
| 4914 | } | ||
| 4915 | /* Check if the storage engine supports indexes on virtual columns. */ | ||
| 4916 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5292 times.
|
5292 | if (!(file->ha_table_flags() & HA_CAN_INDEX_VIRTUAL_GENERATED_COLUMN)) { |
| 4917 | ✗ | my_error(ER_ILLEGAL_HA_CREATE_OPTION, MYF(0), | |
| 4918 | ✗ | ha_resolve_storage_engine_name(file->ht), | |
| 4919 | "Index on virtual generated column"); | ||
| 4920 | ✗ | return true; | |
| 4921 | } | ||
| 4922 | 5292 | key_info->flags |= HA_VIRTUAL_GEN_KEY; | |
| 4923 | } | ||
| 4924 | |||
| 4925 | // JSON columns cannot be used as keys. | ||
| 4926 |
2/2✓ Branch 0 taken 41 times.
✓ Branch 1 taken 2332253 times.
|
2332294 | if (sql_field->sql_type == MYSQL_TYPE_JSON) { |
| 4927 |
1/2✓ Branch 0 taken 41 times.
✗ Branch 1 not taken.
|
41 | my_error(ER_JSON_USED_AS_KEY, MYF(0), column->get_field_name()); |
| 4928 | 41 | return true; | |
| 4929 | } | ||
| 4930 | |||
| 4931 |
2/2✓ Branch 0 taken 246190 times.
✓ Branch 1 taken 2086063 times.
|
2332253 | if (sql_field->auto_flags & Field::NEXT_NUMBER) { |
| 4932 |
6/6✓ Branch 0 taken 111 times.
✓ Branch 1 taken 246079 times.
✓ Branch 2 taken 26 times.
✓ Branch 3 taken 85 times.
✓ Branch 4 taken 246105 times.
✓ Branch 5 taken 85 times.
|
246190 | if (column_nr == 0 || (file->ha_table_flags() & HA_AUTO_PART_KEY)) |
| 4933 | 246105 | (*auto_increment)--; // Field is used | |
| 4934 | } | ||
| 4935 | |||
| 4936 | /* | ||
| 4937 | Check for duplicate columns. | ||
| 4938 | */ | ||
| 4939 |
1/2✓ Branch 0 taken 3613667 times.
✗ Branch 1 not taken.
|
3613666 | for (const Key_part_spec *dup_column : key->columns) { |
| 4940 |
2/2✓ Branch 0 taken 2332232 times.
✓ Branch 1 taken 1281435 times.
|
3613667 | if (dup_column == column) break; |
| 4941 |
3/4✓ Branch 0 taken 1281435 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 22 times.
✓ Branch 3 taken 1281413 times.
|
1281435 | if (!my_strcasecmp(system_charset_info, column->get_field_name(), |
| 4942 | dup_column->get_field_name())) { | ||
| 4943 |
1/2✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
|
22 | my_error(ER_DUP_FIELDNAME, MYF(0), column->get_field_name()); |
| 4944 | 22 | return true; | |
| 4945 | } | ||
| 4946 | } | ||
| 4947 | |||
| 4948 | /* compressed column is not allowed to be defined as a key part */ | ||
| 4949 |
2/4✓ Branch 0 taken 2332231 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2332231 times.
|
2332232 | DBUG_EXECUTE_IF("remove_compressed_attributes_for_keys", |
| 4950 | sql_field->set_column_format(COLUMN_FORMAT_TYPE_DEFAULT);); | ||
| 4951 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2332231 times.
|
2332231 | if (sql_field->column_format() == COLUMN_FORMAT_TYPE_COMPRESSED) { |
| 4952 |
0/2✗ Branch 0 not taken.
✗ Branch 1 not taken.
|
1 | my_error(ER_COMPRESSED_COLUMN_USED_AS_KEY, MYF(0), |
| 4953 | column->get_field_name()); | ||
| 4954 | ✗ | return true; | |
| 4955 | } | ||
| 4956 | |||
| 4957 | uint column_length; | ||
| 4958 |
2/2✓ Branch 0 taken 2922 times.
✓ Branch 1 taken 2329309 times.
|
2332231 | if (key->type == KEYTYPE_FULLTEXT) { |
| 4959 | 8174 | if ((sql_field->sql_type != MYSQL_TYPE_STRING && | |
| 4960 |
2/2✓ Branch 0 taken 1045 times.
✓ Branch 1 taken 1285 times.
|
2330 | sql_field->sql_type != MYSQL_TYPE_VARCHAR && |
| 4961 |
2/2✓ Branch 0 taken 1037 times.
✓ Branch 1 taken 8 times.
|
1045 | !is_blob(sql_field->sql_type)) || |
| 4962 |
1/2✓ Branch 0 taken 2914 times.
✗ Branch 1 not taken.
|
2914 | sql_field->charset == &my_charset_bin || |
| 4963 |
6/6✓ Branch 0 taken 2330 times.
✓ Branch 1 taken 592 times.
✓ Branch 2 taken 2912 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 2910 times.
|
8756 | sql_field->charset->mbminlen > 1 || // ucs2 doesn't work yet |
| 4964 |
4/4✓ Branch 0 taken 485 times.
✓ Branch 1 taken 2427 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 483 times.
|
2912 | (*ft_key_charset && sql_field->charset != *ft_key_charset)) { |
| 4965 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | my_error(ER_BAD_FT_COLUMN, MYF(0), column->get_field_name()); |
| 4966 | 12 | return true; | |
| 4967 | } | ||
| 4968 | 2910 | *ft_key_charset = sql_field->charset; | |
| 4969 | /* | ||
| 4970 | for fulltext keys keyseg length is 1 for blobs (it's ignored in ft | ||
| 4971 | code anyway, and 0 (set to column width later) for char's. it has | ||
| 4972 | to be correct col width for char's, as char data are not prefixed | ||
| 4973 | with length (unlike blobs, where ft code takes data length from a | ||
| 4974 | data prefix, ignoring column->length). | ||
| 4975 | */ | ||
| 4976 | 2910 | column_length = is_blob(sql_field->sql_type); | |
| 4977 | } else { | ||
| 4978 |
3/3✓ Branch 0 taken 1378 times.
✓ Branch 1 taken 980725 times.
✓ Branch 2 taken 1347206 times.
|
2329309 | switch (sql_field->sql_type) { |
| 4979 | 1378 | case MYSQL_TYPE_GEOMETRY: | |
| 4980 | /* All indexes on geometry columns are R-tree indexes. */ | ||
| 4981 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 1366 times.
|
1378 | if (key->columns.size() > 1) { |
| 4982 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | my_error(ER_TOO_MANY_KEY_PARTS, MYF(0), 1); |
| 4983 | 12 | return true; | |
| 4984 | } | ||
| 4985 | 1366 | key_info->flags |= HA_SPATIAL; | |
| 4986 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 1350 times.
|
1366 | if (key->key_create_info.is_algorithm_explicit && |
| 4987 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 3 times.
|
16 | key_info->algorithm != HA_KEY_ALG_RTREE) { |
| 4988 |
3/4✓ Branch 0 taken 7 times.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
|
13 | assert(key->key_create_info.algorithm == HA_KEY_ALG_HASH || |
| 4989 | key->key_create_info.algorithm == HA_KEY_ALG_BTREE); | ||
| 4990 |
1/2✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
|
13 | my_error(ER_INDEX_TYPE_NOT_SUPPORTED_FOR_SPATIAL_INDEX, MYF(0), |
| 4991 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 7 times.
|
13 | key->key_create_info.algorithm == HA_KEY_ALG_HASH ? "HASH" |
| 4992 | : "BTREE"); | ||
| 4993 | 13 | return true; | |
| 4994 | } | ||
| 4995 | 1353 | key_info->algorithm = HA_KEY_ALG_RTREE; | |
| 4996 | [[fallthrough]]; | ||
| 4997 | 982078 | case MYSQL_TYPE_TINY_BLOB: | |
| 4998 | case MYSQL_TYPE_MEDIUM_BLOB: | ||
| 4999 | case MYSQL_TYPE_LONG_BLOB: | ||
| 5000 | case MYSQL_TYPE_BLOB: | ||
| 5001 | case MYSQL_TYPE_JSON: | ||
| 5002 | case MYSQL_TYPE_VAR_STRING: | ||
| 5003 | case MYSQL_TYPE_STRING: | ||
| 5004 | case MYSQL_TYPE_VARCHAR: | ||
| 5005 | case MYSQL_TYPE_ENUM: | ||
| 5006 | case MYSQL_TYPE_SET: | ||
| 5007 | 982078 | column_length = | |
| 5008 | 982078 | column->get_prefix_length() * sql_field->charset->mbmaxlen; | |
| 5009 | 982078 | break; | |
| 5010 | 1347206 | default: | |
| 5011 | 1347206 | column_length = column->get_prefix_length(); | |
| 5012 | } | ||
| 5013 | |||
| 5014 |
2/2✓ Branch 0 taken 2327978 times.
✓ Branch 1 taken 1306 times.
|
2329284 | if (key->type == KEYTYPE_SPATIAL || |
| 5015 |
2/2✓ Branch 0 taken 2327919 times.
✓ Branch 1 taken 59 times.
|
2327978 | key_info->algorithm == HA_KEY_ALG_RTREE || |
| 5016 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2327918 times.
|
2327919 | sql_field->sql_type == MYSQL_TYPE_GEOMETRY) { |
| 5017 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1353 times.
|
1366 | if (column_length) { |
| 5018 |
1/2✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
|
13 | my_error(ER_WRONG_SUB_KEY, MYF(0)); |
| 5019 | 13 | return true; | |
| 5020 | } | ||
| 5021 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1340 times.
|
1353 | if (sql_field->sql_type != MYSQL_TYPE_GEOMETRY) { |
| 5022 |
1/2✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
|
13 | my_error(ER_SPATIAL_MUST_HAVE_GEOM_COL, MYF(0)); |
| 5023 | 13 | return true; | |
| 5024 | } | ||
| 5025 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 1325 times.
|
1340 | if (key_info->flags & HA_NOSAME) { |
| 5026 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
15 | my_error(ER_SPATIAL_UNIQUE_INDEX, MYF(0)); |
| 5027 | 15 | return true; | |
| 5028 | } | ||
| 5029 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 1313 times.
|
1325 | if (column->is_explicit()) { |
| 5030 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | my_error(ER_WRONG_USAGE, MYF(0), "spatial/fulltext/hash index", |
| 5031 | "explicit index order"); | ||
| 5032 | 12 | return true; | |
| 5033 | } | ||
| 5034 | |||
| 5035 | /* | ||
| 5036 | If the field is without an SRID specification, issue a warning telling | ||
| 5037 | the user that this index will not be used by the optimizer (useless | ||
| 5038 | spatial index). We do however have to allow creating such index in | ||
| 5039 | order to support dump/restore from older MySQL versions to new | ||
| 5040 | versions. | ||
| 5041 | |||
| 5042 | NOTE: At this stage of ALTER TABLE/CREATE INDEX/whatever DDL, we may | ||
| 5043 | have copied all existing indexes into key list. Thus, this function may | ||
| 5044 | run for indexes that already exists. The variable | ||
| 5045 | "check_for_duplicate_indexes" will however be set to "false" for indexes | ||
| 5046 | that already are created, so we use this variable to distinguish between | ||
| 5047 | indexes that are to be created, and those that already are created. | ||
| 5048 | */ | ||
| 5049 |
6/6✓ Branch 0 taken 1192 times.
✓ Branch 1 taken 121 times.
✓ Branch 2 taken 34 times.
✓ Branch 3 taken 1158 times.
✓ Branch 4 taken 34 times.
✓ Branch 5 taken 1279 times.
|
1313 | if (key->check_for_duplicate_indexes && !sql_field->m_srid.has_value()) { |
| 5050 |
2/4✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 34 times.
✗ Branch 3 not taken.
|
34 | push_warning_printf( |
| 5051 | thd, Sql_condition::SL_WARNING, WARN_USELESS_SPATIAL_INDEX, | ||
| 5052 | ER_THD(thd, WARN_USELESS_SPATIAL_INDEX), sql_field->field_name); | ||
| 5053 | } | ||
| 5054 | |||
| 5055 | /* | ||
| 5056 | 4 is: (Xmin,Xmax,Ymin,Ymax), this is for 2D case | ||
| 5057 | Lately we'll extend this code to support more dimensions | ||
| 5058 | */ | ||
| 5059 | 1313 | column_length = 4 * sizeof(double); | |
| 5060 | } | ||
| 5061 | |||
| 5062 |
2/2✓ Branch 0 taken 9195 times.
✓ Branch 1 taken 2320037 times.
|
2329231 | if (is_blob(sql_field->sql_type)) { |
| 5063 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9195 times.
|
9195 | if (!(file->ha_table_flags() & HA_CAN_INDEX_BLOBS)) { |
| 5064 | ✗ | my_error(ER_BLOB_USED_AS_KEY, MYF(0), column->get_field_name()); | |
| 5065 | ✗ | return true; | |
| 5066 | } | ||
| 5067 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 9191 times.
|
9195 | if (!column_length) { |
| 5068 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | my_error(ER_BLOB_KEY_WITHOUT_LENGTH, MYF(0), column->get_field_name()); |
| 5069 | 4 | return true; | |
| 5070 | } | ||
| 5071 | } | ||
| 5072 | |||
| 5073 |
2/2✓ Branch 0 taken 780918 times.
✓ Branch 1 taken 1548310 times.
|
2329228 | if (key->type == KEYTYPE_PRIMARY) { |
| 5074 | /* | ||
| 5075 | Set NO_DEFAULT_VALUE_FLAG for the PRIMARY KEY column if default | ||
| 5076 | values is not explicitly provided for the column in CREATE TABLE | ||
| 5077 | statement and it is not an AUTO_INCREMENT field. | ||
| 5078 | |||
| 5079 | Default values for TIMESTAMP/DATETIME needs special handling as: | ||
| 5080 | |||
| 5081 | a) If default is explicitly specified (lets say this as case 1) : | ||
| 5082 | DEFAULT CURRENT_TIMESTAMP | ||
| 5083 | DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | ||
| 5084 | MySQL does not set sql_field->def flag , but sets | ||
| 5085 | Field::DEFAULT_NOW in Create_info::auto_flags. | ||
| 5086 | This flags are also set during timestamp column promotion (case2) | ||
| 5087 | |||
| 5088 | When explicit_defaults_for_timestamp is not set, the behavior | ||
| 5089 | expected in both case1 and case2 is to retain the defaults even | ||
| 5090 | when the column participates in PRIMARY KEY. When | ||
| 5091 | explicit_defaults_for_timestamp is set, the promotion logic | ||
| 5092 | is disabled and the above mentioned flag is not used implicitly. | ||
| 5093 | |||
| 5094 | b) If explicit_defaults_for_timestamp variable is not set: | ||
| 5095 | Default value assigned due to first timestamp column promotion is | ||
| 5096 | retained. | ||
| 5097 | Default constant value assigned due to implicit promotion of second | ||
| 5098 | timestamp column is removed. | ||
| 5099 | */ | ||
| 5100 | 2268762 | if (!sql_field->constant_default && | |
| 5101 |
2/2✓ Branch 0 taken 469225 times.
✓ Branch 1 taken 237701 times.
|
706926 | !(sql_field->flags & AUTO_INCREMENT_FLAG) && |
| 5102 |
2/2✓ Branch 0 taken 1546 times.
✓ Branch 1 taken 467679 times.
|
469225 | !(real_type_with_now_as_default(sql_field->sql_type) && |
| 5103 |
6/6✓ Branch 0 taken 706926 times.
✓ Branch 1 taken 73992 times.
✓ Branch 2 taken 799 times.
✓ Branch 3 taken 747 times.
✓ Branch 4 taken 468463 times.
✓ Branch 5 taken 312455 times.
|
1488643 | (sql_field->auto_flags & Field::DEFAULT_NOW)) && |
| 5104 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 468464 times.
|
468478 | !(sql_field->m_default_val_expr && |
| 5105 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | (sql_field->auto_flags & Field::GENERATED_FROM_EXPRESSION))) { |
| 5106 | 468463 | sql_field->flags |= NO_DEFAULT_VALUE_FLAG; | |
| 5107 | } | ||
| 5108 | /* | ||
| 5109 | Emitting error when field is a part of primary key and is | ||
| 5110 | explicitly requested to be NULL by the user. | ||
| 5111 | */ | ||
| 5112 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 780916 times.
|
780918 | if ((sql_field->flags & EXPLICIT_NULL_FLAG)) { |
| 5113 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | my_error(ER_PRIMARY_CANT_HAVE_NULL, MYF(0)); |
| 5114 | 2 | return true; | |
| 5115 | } | ||
| 5116 | } | ||
| 5117 | |||
| 5118 |
2/2✓ Branch 0 taken 321063 times.
✓ Branch 1 taken 2008163 times.
|
2329226 | if (!(sql_field->flags & NOT_NULL_FLAG)) { |
| 5119 |
2/2✓ Branch 0 taken 10973 times.
✓ Branch 1 taken 310090 times.
|
321063 | if (key->type == KEYTYPE_PRIMARY) { |
| 5120 | /* Implicitly set primary key fields to NOT NULL for ISO conf. */ | ||
| 5121 | 10973 | sql_field->flags |= NOT_NULL_FLAG; | |
| 5122 | 10973 | sql_field->is_nullable = false; | |
| 5123 | 10973 | create_info->null_bits--; | |
| 5124 | } else { | ||
| 5125 | 310090 | key_info->flags |= HA_NULL_PART_KEY; | |
| 5126 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 310090 times.
|
310090 | if (!(file->ha_table_flags() & HA_NULL_IN_KEY)) { |
| 5127 | ✗ | my_error(ER_NULL_COLUMN_IN_INDEX, MYF(0), column->get_field_name()); | |
| 5128 | ✗ | return true; | |
| 5129 | } | ||
| 5130 |
2/2✓ Branch 0 taken 310085 times.
✓ Branch 1 taken 5 times.
|
310090 | if (key->type == KEYTYPE_SPATIAL || |
| 5131 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 310081 times.
|
310085 | sql_field->sql_type == MYSQL_TYPE_GEOMETRY) { |
| 5132 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
9 | my_error(ER_SPATIAL_CANT_HAVE_NULL, MYF(0)); |
| 5133 | 9 | return true; | |
| 5134 | } | ||
| 5135 | } | ||
| 5136 | } | ||
| 5137 | } // key->type != KEYTYPE_FULLTEXT | ||
| 5138 | |||
| 5139 | 2332127 | key_part_info->fieldnr = field; | |
| 5140 | 2332127 | key_part_info->offset = static_cast<uint16>(sql_field->offset); | |
| 5141 |
2/2✓ Branch 0 taken 2331225 times.
✓ Branch 1 taken 901 times.
|
2332127 | key_part_info->key_part_flag |= column->is_ascending() ? 0 : HA_REVERSE_SORT; |
| 5142 | |||
| 5143 |
1/2✓ Branch 0 taken 2332127 times.
✗ Branch 1 not taken.
|
2332126 | size_t key_part_length = sql_field->key_length(); |
| 5144 | |||
| 5145 |
2/2✓ Branch 0 taken 13601 times.
✓ Branch 1 taken 2318526 times.
|
2332127 | if (column_length) { |
| 5146 |
2/2✓ Branch 0 taken 10228 times.
✓ Branch 1 taken 3373 times.
|
13601 | if (is_blob(sql_field->sql_type)) { |
| 5147 | 10228 | key_part_length = column_length; | |
| 5148 | /* | ||
| 5149 | There is a possibility that the given prefix length is less | ||
| 5150 | than the engine max key part length, but still greater | ||
| 5151 | than the BLOB field max size. We handle this case | ||
| 5152 | using the max_field_size variable below. | ||
| 5153 | */ | ||
| 5154 | 10228 | size_t max_field_size = blob_length_by_type(sql_field->sql_type); | |
| 5155 | 30670 | if (key_part_length > max_field_size || | |
| 5156 |
7/8✓ Branch 0 taken 10214 times.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 10214 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10165 times.
✓ Branch 5 taken 49 times.
✓ Branch 6 taken 90 times.
✓ Branch 7 taken 10138 times.
|
20393 | key_part_length > file->max_key_length() || |
| 5157 |
3/4✓ Branch 0 taken 10165 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
✓ Branch 3 taken 10138 times.
|
10165 | key_part_length > file->max_key_part_length(create_info)) { |
| 5158 | // Given prefix length is too large, adjust it. | ||
| 5159 | 90 | key_part_length = | |
| 5160 |
2/4✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 90 times.
✗ Branch 3 not taken.
|
90 | min(file->max_key_length(), file->max_key_part_length(create_info)); |
| 5161 |
1/2✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
|
90 | if (max_field_size) |
| 5162 | 90 | key_part_length = min(key_part_length, max_field_size); | |
| 5163 |
2/2✓ Branch 0 taken 75 times.
✓ Branch 1 taken 15 times.
|
90 | if (key->type & KEYTYPE_MULTIPLE) { |
| 5164 | /* not a critical problem */ | ||
| 5165 |
2/4✓ Branch 0 taken 75 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 75 times.
✗ Branch 3 not taken.
|
75 | push_warning_printf(thd, Sql_condition::SL_WARNING, ER_TOO_LONG_KEY, |
| 5166 | ER_THD(thd, ER_TOO_LONG_KEY), | ||
| 5167 | static_cast<int>(key_part_length)); | ||
| 5168 | /* Align key length to multibyte char boundary */ | ||
| 5169 | 75 | key_part_length -= key_part_length % sql_field->charset->mbmaxlen; | |
| 5170 | /* | ||
| 5171 | If SQL_MODE is STRICT, then report error, else report warning | ||
| 5172 | and continue execution. | ||
| 5173 | */ | ||
| 5174 |
3/4✓ Branch 0 taken 75 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 43 times.
✓ Branch 3 taken 32 times.
|
90 | if (thd->is_error()) return true; |
| 5175 | } else { | ||
| 5176 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
15 | my_error(ER_TOO_LONG_KEY, MYF(0), key_part_length); |
| 5177 |
2/4✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
|
15 | if (thd->is_error()) return true; |
| 5178 | } | ||
| 5179 | } | ||
| 5180 | } // is_blob | ||
| 5181 | // Catch invalid use of partial keys | ||
| 5182 | 8815 | else if (sql_field->sql_type != MYSQL_TYPE_GEOMETRY && | |
| 5183 | // is the key partial? | ||
| 5184 |
6/6✓ Branch 0 taken 2069 times.
✓ Branch 1 taken 1304 times.
✓ Branch 2 taken 1768 times.
✓ Branch 3 taken 301 times.
✓ Branch 4 taken 10 times.
✓ Branch 5 taken 3363 times.
|
5141 | column_length != key_part_length && |
| 5185 | // is prefix length bigger than field length? | ||
| 5186 |
2/2✓ Branch 0 taken 1759 times.
✓ Branch 1 taken 9 times.
|
1768 | (column_length > key_part_length || |
| 5187 | // can the field have a partial key? | ||
| 5188 |
3/4✓ Branch 0 taken 1759 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1758 times.
✓ Branch 3 taken 1 times.
|
1759 | !Field::type_can_have_key_part(sql_field->sql_type) || |
| 5189 | // does the storage engine allow prefixed search? | ||
| 5190 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1758 times.
|
1758 | ((file->ha_table_flags() & HA_NO_PREFIX_CHAR_KEYS) && |
| 5191 | // and is this a 'unique' key? | ||
| 5192 | ✗ | (key_info->flags & HA_NOSAME)))) { | |
| 5193 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | my_error(ER_WRONG_SUB_KEY, MYF(0)); |
| 5194 | 10 | return true; | |
| 5195 |
1/2✓ Branch 0 taken 3363 times.
✗ Branch 1 not taken.
|
3363 | } else if (!(file->ha_table_flags() & HA_NO_PREFIX_CHAR_KEYS)) |
| 5196 | 3363 | key_part_length = column_length; | |
| 5197 | } // column_length | ||
| 5198 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2318523 times.
|
2318526 | else if (key_part_length == 0) { |
| 5199 |
3/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 times.
|
3 | if (is_field_for_functional_index(sql_field)) { |
| 5200 | // In case this is a functional index, print a more friendly error | ||
| 5201 | // message. | ||
| 5202 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | Item *expression = column->get_expression(); |
| 5203 | 2 | auto flags = | |
| 5204 | enum_query_type(QT_NO_DB | QT_NO_TABLE | QT_FORCE_INTRODUCERS); | ||
| 5205 | 2 | String out; | |
| 5206 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | expression->print(thd, &out, flags); |
| 5207 | |||
| 5208 | // Append a NULL-terminator, since Item::print does not necessarily add | ||
| 5209 | // one. | ||
| 5210 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | out.append('\0'); |
| 5211 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | my_error(ER_WRONG_KEY_COLUMN_FUNCTIONAL_INDEX, MYF(0), out.ptr()); |
| 5212 | 2 | } else { | |
| 5213 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_WRONG_KEY_COLUMN, MYF(0), column->get_field_name()); |
| 5214 | } | ||
| 5215 | 3 | return true; | |
| 5216 | } | ||
| 5217 | |||
| 5218 |
5/6✓ Branch 0 taken 2332055 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 79 times.
✓ Branch 3 taken 2331976 times.
✓ Branch 4 taken 48 times.
✓ Branch 5 taken 2332007 times.
|
2332135 | if (key_part_length > file->max_key_part_length(create_info) && |
| 5219 |
2/2✓ Branch 0 taken 48 times.
✓ Branch 1 taken 31 times.
|
79 | key->type != KEYTYPE_FULLTEXT) { |
| 5220 |
1/2✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
|
48 | key_part_length = file->max_key_part_length(create_info); |
| 5221 |
2/2✓ Branch 0 taken 34 times.
✓ Branch 1 taken 14 times.
|
48 | if (key->type & KEYTYPE_MULTIPLE) { |
| 5222 | /* not a critical problem */ | ||
| 5223 |
2/4✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 34 times.
✗ Branch 3 not taken.
|
34 | push_warning_printf(thd, Sql_condition::SL_WARNING, ER_TOO_LONG_KEY, |
| 5224 | ER_THD(thd, ER_TOO_LONG_KEY), | ||
| 5225 | static_cast<int>(key_part_length)); | ||
| 5226 | /* Align key length to multibyte char boundary */ | ||
| 5227 | 34 | key_part_length -= key_part_length % sql_field->charset->mbmaxlen; | |
| 5228 | /* | ||
| 5229 | If SQL_MODE is STRICT, then report error, else report warning | ||
| 5230 | and continue execution. | ||
| 5231 | */ | ||
| 5232 |
3/4✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 21 times.
|
34 | if (thd->is_error()) return true; |
| 5233 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
|
14 | } else if ((thd->lex->alter_info->flags & Alter_info::ALTER_OPTIONS) && |
| 5234 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 12 times.
|
13 | (create_info->used_fields & HA_CREATE_USED_CHARSET)) { |
| 5235 | 1 | my_error(ER_COLUMN_CHANGE_SIZE, MYF(0), sql_field->field_name, | |
| 5236 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | sql_field->field->table->s->table_name.str, key->name.str, |
| 5237 | key_part_length); | ||
| 5238 | 1 | return true; | |
| 5239 | } else { | ||
| 5240 |
1/2✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
|
13 | my_error(ER_TOO_LONG_KEY, MYF(0), key_part_length); |
| 5241 |
3/4✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 1 times.
|
13 | if (thd->is_error()) return true; |
| 5242 | } | ||
| 5243 | } | ||
| 5244 | 2332029 | key_part_info->length = static_cast<uint16>(key_part_length); | |
| 5245 | |||
| 5246 | /* | ||
| 5247 | Use packed keys for long strings on the first column | ||
| 5248 | |||
| 5249 | Due to incorrect usage of sql_field->pack_flag & FIELDFLAG_BLOB check | ||
| 5250 | we have used packing for some columns which are not strings or BLOBs | ||
| 5251 | (see also is_phony_blob()). Since changing this would mean breaking | ||
| 5252 | binary compatibility for MyISAM tables with indexes on such columns | ||
| 5253 | we mimic this buggy behavior here. | ||
| 5254 | */ | ||
| 5255 | 4695853 | if ((create_info->db_type->flags & HTON_SUPPORTS_PACKED_KEYS) && | |
| 5256 |
6/6✓ Branch 0 taken 31795 times.
✓ Branch 1 taken 2300234 times.
✓ Branch 2 taken 31792 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 13692 times.
✓ Branch 5 taken 2318337 times.
|
2363821 | !((create_info->table_options & HA_OPTION_NO_PACK_KEYS)) && |
| 5257 |
2/2✓ Branch 0 taken 23562 times.
✓ Branch 1 taken 8230 times.
|
31792 | (key_part_length >= KEY_DEFAULT_PACK_LENGTH && |
| 5258 |
2/2✓ Branch 0 taken 10642 times.
✓ Branch 1 taken 12920 times.
|
23562 | (sql_field->sql_type == MYSQL_TYPE_STRING || |
| 5259 |
4/4✓ Branch 0 taken 10185 times.
✓ Branch 1 taken 457 times.
✓ Branch 2 taken 9877 times.
✓ Branch 3 taken 308 times.
|
20827 | sql_field->sql_type == MYSQL_TYPE_VARCHAR || |
| 5260 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 9870 times.
|
20062 | is_blob(sql_field->sql_type) || |
| 5261 | 9877 | is_phony_blob(sql_field->sql_type, sql_field->decimals)))) { | |
| 5262 |
2/2✓ Branch 0 taken 6359 times.
✓ Branch 1 taken 285 times.
|
6644 | if ((column_nr == 0 && |
| 5263 |
2/2✓ Branch 0 taken 6352 times.
✓ Branch 1 taken 7 times.
|
13003 | (is_blob(sql_field->sql_type) || |
| 5264 |
4/4✓ Branch 0 taken 6644 times.
✓ Branch 1 taken 7048 times.
✓ Branch 2 taken 749 times.
✓ Branch 3 taken 12943 times.
|
33743 | is_phony_blob(sql_field->sql_type, sql_field->decimals))) || |
| 5265 |
2/2✓ Branch 0 taken 457 times.
✓ Branch 1 taken 12943 times.
|
13400 | sql_field->sql_type == MYSQL_TYPE_VARCHAR) |
| 5266 | 749 | key_info->flags |= HA_BINARY_PACK_KEY; | |
| 5267 | else | ||
| 5268 | 12943 | key_info->flags |= HA_PACK_KEY; | |
| 5269 | } | ||
| 5270 | |||
| 5271 | /* | ||
| 5272 | Check if the key segment is partial, set the key flag | ||
| 5273 | accordingly. Note that fulltext indexes ignores prefixes. | ||
| 5274 | */ | ||
| 5275 |
4/4✓ Branch 0 taken 2329119 times.
✓ Branch 1 taken 2910 times.
✓ Branch 2 taken 11911 times.
✓ Branch 3 taken 2320119 times.
|
4661149 | if (key->type != KEYTYPE_FULLTEXT && |
| 5276 |
3/4✓ Branch 0 taken 2329120 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11911 times.
✓ Branch 3 taken 2317209 times.
|
2329119 | key_part_length != sql_field->key_length()) { |
| 5277 | 11911 | key_info->flags |= HA_KEY_HAS_PART_KEY_SEG; | |
| 5278 | 11911 | key_part_info->key_part_flag |= HA_PART_KEY_SEG; | |
| 5279 | } | ||
| 5280 | |||
| 5281 | 2332030 | key_info->key_length += key_part_length; | |
| 5282 | 2332030 | return false; | |
| 5283 | 2332320 | } | |
| 5284 | |||
| 5285 | /** | ||
| 5286 | Check if candidate parent/supporting key contains exactly the same | ||
| 5287 | columns as the foreign key, possibly, in different order. Also check | ||
| 5288 | that columns usage by key is acceptable, i.e. key is not over column | ||
| 5289 | prefix. | ||
| 5290 | |||
| 5291 | @tparam F Function class which returns foreign key's | ||
| 5292 | referenced or referencing (depending on whether | ||
| 5293 | we check candidate parent or supporting key) | ||
| 5294 | column name by its index. | ||
| 5295 | @param alter_info Alter_info describing columns in parent or | ||
| 5296 | child table. | ||
| 5297 | @param fk_col_count Number of columns in the foreign key. | ||
| 5298 | @param fk_columns Object of F type bound to the specific foreign key | ||
| 5299 | for which parent/supporting key check is carried | ||
| 5300 | out. | ||
| 5301 | @param key KEY object describing candidate parent/supporting | ||
| 5302 | key. | ||
| 5303 | |||
| 5304 | @sa fk_is_key_exact_match_any_order(uint, F, dd::Index). | ||
| 5305 | |||
| 5306 | @retval True - Key is proper parent/supporting key for the foreign key. | ||
| 5307 | @retval False - Key can't be parent/supporting key for the foreign key. | ||
| 5308 | */ | ||
| 5309 | template <class F> | ||
| 5310 | ✗ | static bool fk_is_key_exact_match_any_order(Alter_info *alter_info, | |
| 5311 | uint fk_col_count, | ||
| 5312 | const F &fk_columns, | ||
| 5313 | const KEY *key) { | ||
| 5314 | ✗ | if (fk_col_count != key->user_defined_key_parts) return false; | |
| 5315 | |||
| 5316 | ✗ | for (uint i = 0; i < key->user_defined_key_parts; i++) { | |
| 5317 | // Prefix parts are considered non-matching. | ||
| 5318 | ✗ | if (key->key_part[i].key_part_flag & HA_PART_KEY_SEG) return false; | |
| 5319 | |||
| 5320 | const Create_field *col = | ||
| 5321 | ✗ | get_field_by_index(alter_info, key->key_part[i].fieldnr); | |
| 5322 | |||
| 5323 | ✗ | uint j = 0; | |
| 5324 | ✗ | while (j < fk_col_count) { | |
| 5325 | ✗ | if (my_strcasecmp(system_charset_info, col->field_name, fk_columns(j)) == | |
| 5326 | 0) | ||
| 5327 | ✗ | break; | |
| 5328 | ✗ | j++; | |
| 5329 | } | ||
| 5330 | ✗ | if (j == fk_col_count) return false; | |
| 5331 | |||
| 5332 | /* | ||
| 5333 | Foreign keys over virtual columns are not allowed. | ||
| 5334 | This is checked at earlier stage. | ||
| 5335 | */ | ||
| 5336 | ✗ | assert(!col->is_virtual_gcol()); | |
| 5337 | } | ||
| 5338 | |||
| 5339 | ✗ | return true; | |
| 5340 | } | ||
| 5341 | |||
| 5342 | /** | ||
| 5343 | Count how many elements from the start of the candidate parent/supporting | ||
| 5344 | key match elements at the start of the foreign key (prefix parts are | ||
| 5345 | considered non-matching). | ||
| 5346 | |||
| 5347 | @tparam F Function class which returns foreign key's | ||
| 5348 | referenced or referencing (depending on whether | ||
| 5349 | we check candidate parent or supporting key) | ||
| 5350 | column name by its index. | ||
| 5351 | @param alter_info Alter_info describing columns in parent or | ||
| 5352 | child table. | ||
| 5353 | @param fk_col_count Number of columns in the foreign key. | ||
| 5354 | @param fk_columns Object of F type bound to the specific foreign key | ||
| 5355 | for which parent/supporting key check is carried | ||
| 5356 | out. | ||
| 5357 | @param key KEY object describing candidate parent/supporting | ||
| 5358 | key. | ||
| 5359 | @param hidden_cols_key If non-nullptr, points to KEY object representing | ||
| 5360 | primary key for the table, which columns are added | ||
| 5361 | to the candidate parent key and should be taken | ||
| 5362 | into account when considering this parent key. | ||
| 5363 | |||
| 5364 | @sa fk_key_prefix_match_count(uint, F, dd::Index, bool). | ||
| 5365 | |||
| 5366 | @retval Number of matching columns. | ||
| 5367 | */ | ||
| 5368 | template <class F> | ||
| 5369 | 3914148 | static uint fk_key_prefix_match_count(Alter_info *alter_info, uint fk_col_count, | |
| 5370 | const F &fk_columns, const KEY *key, | ||
| 5371 | const KEY *hidden_cols_key) { | ||
| 5372 | 3914148 | uint col_idx = 0; | |
| 5373 | |||
| 5374 |
2/2✓ Branch 0 taken 2245169 times.
✓ Branch 1 taken 337447 times.
|
5165232 | for (; col_idx < key->user_defined_key_parts; ++col_idx) { |
| 5375 |
2/2✓ Branch 0 taken 287603 times.
✓ Branch 1 taken 1957566 times.
|
4490338 | if (col_idx == fk_col_count) break; |
| 5376 | // Prefix parts are considered non-matching. | ||
| 5377 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1957560 times.
|
3915132 | if (key->key_part[col_idx].key_part_flag & HA_PART_KEY_SEG) break; |
| 5378 | const Create_field *col = | ||
| 5379 | 3915120 | get_field_by_index(alter_info, key->key_part[col_idx].fieldnr); | |
| 5380 | |||
| 5381 | 3915120 | if (my_strcasecmp(system_charset_info, col->field_name, | |
| 5382 |
2/2✓ Branch 0 taken 1332018 times.
✓ Branch 1 taken 625542 times.
|
3915120 | fk_columns(col_idx)) != 0) |
| 5383 | 2664036 | break; | |
| 5384 | |||
| 5385 | /* | ||
| 5386 | Foreign keys over virtual columns are not allowed. | ||
| 5387 | This is checked at earlier stage. | ||
| 5388 | */ | ||
| 5389 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 625542 times.
|
1251084 | assert(!col->is_virtual_gcol()); |
| 5390 | } | ||
| 5391 | |||
| 5392 |
3/6✓ Branch 0 taken 1332024 times.
✓ Branch 1 taken 625050 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1332024 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
3914148 | if (col_idx < fk_col_count && col_idx == key->user_defined_key_parts && |
| 5393 | hidden_cols_key) { | ||
| 5394 | /* | ||
| 5395 | We have not found all foreign key columns and have not encountered | ||
| 5396 | unsuitable columns so far. Continue counting columns from hidden | ||
| 5397 | part of the key if it exists. | ||
| 5398 | */ | ||
| 5399 | ✗ | for (uint add_col_idx = 0; | |
| 5400 | ✗ | add_col_idx < hidden_cols_key->user_defined_key_parts; ++add_col_idx) { | |
| 5401 | ✗ | if (col_idx == fk_col_count) break; | |
| 5402 | |||
| 5403 | ✗ | KEY_PART_INFO *add_key_part = hidden_cols_key->key_part + add_col_idx; | |
| 5404 | /* | ||
| 5405 | Hidden part of the key doesn't include columns already in the key, | ||
| 5406 | unless they are used as prefix columns (which is impossible here). | ||
| 5407 | */ | ||
| 5408 | ✗ | if (std::any_of(key->key_part, | |
| 5409 | ✗ | key->key_part + key->user_defined_key_parts, | |
| 5410 | ✗ | [add_key_part](const KEY_PART_INFO &key_part) { | |
| 5411 | ✗ | return key_part.fieldnr == add_key_part->fieldnr; | |
| 5412 | })) | ||
| 5413 | ✗ | continue; | |
| 5414 | /* | ||
| 5415 | prepare_self_ref_fk_parent_key() ensures that we can't meet | ||
| 5416 | primary keys with prefix parts here. | ||
| 5417 | */ | ||
| 5418 | ✗ | assert(!(add_key_part->key_part_flag & HA_PART_KEY_SEG)); | |
| 5419 | |||
| 5420 | const Create_field *col = | ||
| 5421 | ✗ | get_field_by_index(alter_info, add_key_part->fieldnr); | |
| 5422 | |||
| 5423 | ✗ | if (my_strcasecmp(system_charset_info, col->field_name, | |
| 5424 | ✗ | fk_columns(col_idx)) != 0) | |
| 5425 | ✗ | break; | |
| 5426 | |||
| 5427 | ✗ | assert(!col->is_virtual_gcol()); | |
| 5428 | ✗ | ++col_idx; | |
| 5429 | } | ||
| 5430 | } | ||
| 5431 | |||
| 5432 | 3914148 | return col_idx; | |
| 5433 | } | ||
| 5434 | |||
| 5435 | /** | ||
| 5436 | Check if candidate parent/supporting key contains all columns from the | ||
| 5437 | foreign key at its start and in the same order it is in the foreign key. | ||
| 5438 | Also check that columns usage by key is acceptable, i.e. key is not over | ||
| 5439 | column prefix. | ||
| 5440 | |||
| 5441 | @tparam F Function class which returns foreign key's | ||
| 5442 | referenced or referencing (depending on whether | ||
| 5443 | we check candidate parent or supporting key) | ||
| 5444 | column name by its index. | ||
| 5445 | @param alter_info Alter_info describing columns in parent or | ||
| 5446 | child table. | ||
| 5447 | @param fk_col_count Number of columns in the foreign key. | ||
| 5448 | @param fk_columns Object of F type bound to the specific foreign key | ||
| 5449 | for which parent/supporting key check is carried | ||
| 5450 | out. | ||
| 5451 | @param key KEY object describing candidate parent/supporting | ||
| 5452 | key. | ||
| 5453 | @param hidden_cols_key If non-nullptr, points to KEY object representing | ||
| 5454 | primary key for the table, which columns are added | ||
| 5455 | to the candidate parent key and should be taken | ||
| 5456 | into account when considering this parent key. | ||
| 5457 | |||
| 5458 | @sa fk_key_is_full_prefix_match(uint, F, dd::Index, bool). | ||
| 5459 | |||
| 5460 | @retval True - Key is proper parent/supporting key for the foreign key. | ||
| 5461 | @retval False - Key can't be parent/supporting key for the foreign key. | ||
| 5462 | */ | ||
| 5463 | template <class F> | ||
| 5464 | 3914324 | static bool fk_key_is_full_prefix_match(Alter_info *alter_info, | |
| 5465 | uint fk_col_count, const F &fk_columns, | ||
| 5466 | const KEY *key, | ||
| 5467 | const KEY *hidden_cols_key) { | ||
| 5468 | /* | ||
| 5469 | The index may have more elements, but must start with the same | ||
| 5470 | elements as the FK. | ||
| 5471 | */ | ||
| 5472 | 3914324 | if (fk_col_count > | |
| 5473 |
2/2✓ Branch 0 taken 88 times.
✓ Branch 1 taken 1957074 times.
|
3914324 | key->user_defined_key_parts + |
| 5474 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1957162 times.
|
3914324 | (hidden_cols_key ? hidden_cols_key->user_defined_key_parts : 0)) |
| 5475 | 176 | return false; | |
| 5476 | |||
| 5477 | 3914148 | uint match_count = fk_key_prefix_match_count( | |
| 5478 | alter_info, fk_col_count, fk_columns, key, hidden_cols_key); | ||
| 5479 | 3914148 | return (match_count == fk_col_count); | |
| 5480 | } | ||
| 5481 | |||
| 5482 | /** | ||
| 5483 | Check if parent key for self-referencing foreign key exists, set | ||
| 5484 | foreign key's unique constraint name accordingly. Emit error if | ||
| 5485 | no parent key found. | ||
| 5486 | |||
| 5487 | @note Prefer unique key if possible. If parent key is non-unique | ||
| 5488 | unique constraint name is set to NULL. | ||
| 5489 | |||
| 5490 | @note Explicitly skip the supporting index as a candidate parent | ||
| 5491 | index to maintain previous behavior for engines that require | ||
| 5492 | the two indexes to be different. | ||
| 5493 | |||
| 5494 | @param hton Handlerton for table's storage engine. | ||
| 5495 | @param alter_info Alter_info object describing parent table. | ||
| 5496 | @param key_info_buffer Array describing keys in parent table. | ||
| 5497 | @param key_count Number of keys in parent table. | ||
| 5498 | @param supporting_key Pointer to KEY representing the supporting | ||
| 5499 | index. | ||
| 5500 | @param old_fk_table dd::Table object from which pre-existing | ||
| 5501 | FK comes from. nullptr if this FK is newly | ||
| 5502 | added. | ||
| 5503 | @param[in,out] fk FOREIGN_KEY object describing the FK, its | ||
| 5504 | unique_index_name member will be updated | ||
| 5505 | if matching unique constraint is found. | ||
| 5506 | |||
| 5507 | @retval Operation result. False if success. | ||
| 5508 | */ | ||
| 5509 | 12012 | static bool prepare_self_ref_fk_parent_key( | |
| 5510 | handlerton *hton, Alter_info *alter_info, const KEY *key_info_buffer, | ||
| 5511 | const uint key_count, const KEY *supporting_key, | ||
| 5512 | const dd::Table *old_fk_table, FOREIGN_KEY *fk) { | ||
| 5513 | 12012 | auto fk_columns_lambda = [fk](uint i) { return fk->fk_key_part[i].str; }; | |
| 5514 |
2/2✓ Branch 0 taken 12013 times.
✓ Branch 1 taken 1 times.
|
12014 | for (const KEY *key = key_info_buffer; key < key_info_buffer + key_count; |
| 5515 | key++) { | ||
| 5516 | // We can't use FULLTEXT or SPATIAL indexes. | ||
| 5517 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12013 times.
|
12013 | if (key->flags & (HA_FULLTEXT | HA_SPATIAL)) continue; |
| 5518 | |||
| 5519 |
1/2✓ Branch 0 taken 12013 times.
✗ Branch 1 not taken.
|
12013 | if (hton->foreign_keys_flags & |
| 5520 | HTON_FKS_NEED_DIFFERENT_PARENT_AND_SUPPORTING_KEYS) { | ||
| 5521 | /* | ||
| 5522 | The storage engine does not support using the same index for both the | ||
| 5523 | supporting index and the parent index. In this case, the supporting | ||
| 5524 | index cannot be a candidate parent index, and must be skipped. | ||
| 5525 | */ | ||
| 5526 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 12012 times.
|
12013 | if (key == supporting_key) continue; |
| 5527 | } | ||
| 5528 | |||
| 5529 |
1/2✓ Branch 0 taken 12012 times.
✗ Branch 1 not taken.
|
12012 | if (hton->foreign_keys_flags & HTON_FKS_WITH_PREFIX_PARENT_KEYS) { |
| 5530 | /* | ||
| 5531 | Engine supports unique and non unique-parent keys which contain full | ||
| 5532 | foreign key as its prefix. Example: InnoDB. | ||
| 5533 | |||
| 5534 | Primary and unique keys are sorted before non-unique keys. | ||
| 5535 | So if there is suitable unique parent key we will always find | ||
| 5536 | it before encountering any non-unique keys. | ||
| 5537 | */ | ||
| 5538 | |||
| 5539 | 12012 | const KEY *hidden_cols_key = nullptr; | |
| 5540 | |||
| 5541 |
1/2✓ Branch 0 taken 12012 times.
✗ Branch 1 not taken.
|
12012 | if (hton->foreign_keys_flags & HTON_FKS_WITH_EXTENDED_PARENT_KEYS) { |
| 5542 | /* | ||
| 5543 | Engine considers hidden part of key (columns from primary key | ||
| 5544 | which are implicitly added to secondary keys) when determines | ||
| 5545 | if it can serve as parent. Example: InnoDB. | ||
| 5546 | |||
| 5547 | Since KEY objects do not contain information about hidden parts | ||
| 5548 | of the keys at this point, we have to figure out list of hidden | ||
| 5549 | columns based on KEY object for explicit or implicit primary key. | ||
| 5550 | For the sake of consistency with non-self-referencing case we | ||
| 5551 | exclude primary keys with prefix elements from our consideration. | ||
| 5552 | |||
| 5553 | Thanks to the way keys are sorted, to find primary key it is | ||
| 5554 | enough to check if the first key in key array satisfies | ||
| 5555 | requirements on candidate key (unique, without null, prefix or | ||
| 5556 | virtual parts). This also automatically excludes explicit primary | ||
| 5557 | keys with prefix parts. | ||
| 5558 | */ | ||
| 5559 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 12012 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
12012 | if (key != key_info_buffer && (key_info_buffer->flags & HA_NOSAME) && |
| 5560 | ✗ | !(key_info_buffer->flags & | |
| 5561 | (HA_NULL_PART_KEY | HA_KEY_HAS_PART_KEY_SEG | | ||
| 5562 | HA_VIRTUAL_GEN_KEY))) | ||
| 5563 | ✗ | hidden_cols_key = key_info_buffer; | |
| 5564 | } | ||
| 5565 | |||
| 5566 |
3/4✓ Branch 0 taken 12012 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12011 times.
✓ Branch 3 taken 1 times.
|
12012 | if (fk_key_is_full_prefix_match(alter_info, fk->key_parts, |
| 5567 | fk_columns_lambda, key, | ||
| 5568 | hidden_cols_key)) { | ||
| 5569 | /* | ||
| 5570 | We only store names of PK or UNIQUE keys in UNIQUE_CONSTRAINT_NAME. | ||
| 5571 | InnoDB allows non-unique indexes as parent keys for which NULL is | ||
| 5572 | stored. | ||
| 5573 | */ | ||
| 5574 |
2/2✓ Branch 0 taken 12009 times.
✓ Branch 1 taken 2 times.
|
12011 | if (key->flags & HA_NOSAME) |
| 5575 | 12009 | fk->unique_index_name = key->name; | |
| 5576 | else | ||
| 5577 | 2 | fk->unique_index_name = nullptr; | |
| 5578 | 12011 | return false; | |
| 5579 | } | ||
| 5580 | } else { | ||
| 5581 | /* | ||
| 5582 | Default case. Engine only supports unique parent keys which | ||
| 5583 | contain exactly the same columns as foreign key, possibly | ||
| 5584 | in different order. Example: NDB. | ||
| 5585 | */ | ||
| 5586 | ✗ | if ((key->flags & HA_NOSAME) && | |
| 5587 | ✗ | fk_is_key_exact_match_any_order(alter_info, fk->key_parts, | |
| 5588 | fk_columns_lambda, key)) { | ||
| 5589 | ✗ | fk->unique_index_name = key->name; | |
| 5590 | ✗ | return false; | |
| 5591 | } | ||
| 5592 | } | ||
| 5593 | } | ||
| 5594 | |||
| 5595 | // No matching parent key! | ||
| 5596 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (old_fk_table == nullptr) { |
| 5597 | // This is new foreign key for which parent key is missing. | ||
| 5598 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_FK_NO_INDEX_PARENT, MYF(0), fk->name, fk->ref_table.str); |
| 5599 | } else { | ||
| 5600 | /* | ||
| 5601 | Old foreign key for which parent key or supporting key must have | ||
| 5602 | been dropped by this ALTER TABLE. Some analysis is needed to determine | ||
| 5603 | what has been dropped. | ||
| 5604 | |||
| 5605 | Find old foreign key definition first. | ||
| 5606 | */ | ||
| 5607 | ✗ | auto same_name = [fk](const dd::Foreign_key *el) { | |
| 5608 | ✗ | return my_strcasecmp(system_charset_info, fk->name, el->name().c_str()) == | |
| 5609 | ✗ | 0; | |
| 5610 | ✗ | }; | |
| 5611 | |||
| 5612 | ✗ | auto old_fk = std::find_if(old_fk_table->foreign_keys().begin(), | |
| 5613 | ✗ | old_fk_table->foreign_keys().end(), same_name); | |
| 5614 | ✗ | assert(old_fk != old_fk_table->foreign_keys().end()); | |
| 5615 | |||
| 5616 | /* | ||
| 5617 | Then, unless the SE supports it, we need to find the old | ||
| 5618 | supporting key, to avoid selecting the incorrect parent key, and to | ||
| 5619 | make sure we determine whether the supporting or the parent key was | ||
| 5620 | dropped. This is done as follows: | ||
| 5621 | |||
| 5622 | - If the name of the old and new supporting key is the same, | ||
| 5623 | then we have either dropped the parent key, or we have dropped | ||
| 5624 | the supporting key and renamed another key to the supporting | ||
| 5625 | key's name. | ||
| 5626 | - If the name of the old and new supporting key is different, | ||
| 5627 | then we have either dropped the supporting key, or we have dropped | ||
| 5628 | the parent key and renamed the supporting key to a different name. | ||
| 5629 | |||
| 5630 | When finding the original key name, just getting the unique constraint | ||
| 5631 | name won't work for non-unique parent keys. Ideally, we should be | ||
| 5632 | using the handlerton of the old table version below, however, in | ||
| 5633 | practice, the new table version's handlerton works just fine, since | ||
| 5634 | we do not allow changing storage engines for tables with foreign keys. | ||
| 5635 | */ | ||
| 5636 | ✗ | const char *dropped_key = "<unknown key name>"; | |
| 5637 | ✗ | if (hton->foreign_keys_flags & | |
| 5638 | HTON_FKS_NEED_DIFFERENT_PARENT_AND_SUPPORTING_KEYS) { | ||
| 5639 | const dd::Index *old_sk = | ||
| 5640 | ✗ | find_fk_supporting_key(hton, old_fk_table, *old_fk); | |
| 5641 | const dd::Index *old_pk = | ||
| 5642 | ✗ | find_fk_parent_key(hton, old_sk, old_fk_table, *old_fk); | |
| 5643 | |||
| 5644 | ✗ | if (old_sk != nullptr && old_pk != nullptr) { | |
| 5645 | ✗ | if (my_strcasecmp(system_charset_info, supporting_key->name, | |
| 5646 | ✗ | old_sk->name().c_str()) == 0) { | |
| 5647 | ✗ | dropped_key = old_pk->name().c_str(); | |
| 5648 | ✗ | auto renamed_to_sk = [supporting_key](const Alter_rename_key *key) { | |
| 5649 | ✗ | return (my_strcasecmp(system_charset_info, supporting_key->name, | |
| 5650 | ✗ | key->new_name) == 0); | |
| 5651 | ✗ | }; | |
| 5652 | ✗ | if (std::any_of(alter_info->alter_rename_key_list.begin(), | |
| 5653 | alter_info->alter_rename_key_list.end(), | ||
| 5654 | renamed_to_sk)) { | ||
| 5655 | ✗ | dropped_key = old_sk->name().c_str(); | |
| 5656 | } | ||
| 5657 | } else { | ||
| 5658 | ✗ | dropped_key = old_sk->name().c_str(); | |
| 5659 | ✗ | auto renamed_from_sk = [old_sk](const Alter_rename_key *key) { | |
| 5660 | ✗ | return (my_strcasecmp(system_charset_info, old_sk->name().c_str(), | |
| 5661 | ✗ | key->old_name) == 0); | |
| 5662 | ✗ | }; | |
| 5663 | ✗ | if (std::any_of(alter_info->alter_rename_key_list.begin(), | |
| 5664 | alter_info->alter_rename_key_list.end(), | ||
| 5665 | renamed_from_sk)) { | ||
| 5666 | ✗ | dropped_key = old_pk->name().c_str(); | |
| 5667 | } | ||
| 5668 | } | ||
| 5669 | } | ||
| 5670 | } else { | ||
| 5671 | const dd::Index *old_pk = | ||
| 5672 | ✗ | find_fk_parent_key(hton, nullptr, old_fk_table, *old_fk); | |
| 5673 | ✗ | if (old_pk) dropped_key = old_pk->name().c_str(); | |
| 5674 | } | ||
| 5675 | |||
| 5676 | ✗ | my_error(ER_DROP_INDEX_FK, MYF(0), dropped_key); | |
| 5677 | } | ||
| 5678 | 1 | return true; | |
| 5679 | } | ||
| 5680 | |||
| 5681 | /** | ||
| 5682 | Find supporting key for the foreign key. | ||
| 5683 | |||
| 5684 | @param hton Handlerton for table's storage engine. | ||
| 5685 | @param alter_info Alter_info object describing child table. | ||
| 5686 | @param key_info_buffer Array describing keys in child table. | ||
| 5687 | @param key_count Number of keys in child table. | ||
| 5688 | @param fk FOREIGN_KEY object describing the FK. | ||
| 5689 | |||
| 5690 | @sa find_fk_supporting_key(handlerton*, const dd::Table*, | ||
| 5691 | const dd::Foreign_key*) | ||
| 5692 | |||
| 5693 | @retval non-nullptr - pointer to KEY object describing supporting key. | ||
| 5694 | @retval nullptr - if no supporting key were found. | ||
| 5695 | */ | ||
| 5696 | 613054 | static const KEY *find_fk_supporting_key(handlerton *hton, | |
| 5697 | Alter_info *alter_info, | ||
| 5698 | const KEY *key_info_buffer, | ||
| 5699 | const uint key_count, | ||
| 5700 | const FOREIGN_KEY *fk) { | ||
| 5701 | 613054 | uint best_match_count = 0; | |
| 5702 | 613054 | const KEY *best_match_key = nullptr; | |
| 5703 | |||
| 5704 | 1945548 | auto fk_columns_lambda = [fk](uint i) { return fk->key_part[i].str; }; | |
| 5705 | |||
| 5706 |
2/2✓ Branch 0 taken 1945155 times.
✓ Branch 1 taken 15 times.
|
1945170 | for (const KEY *key = key_info_buffer; key < key_info_buffer + key_count; |
| 5707 | key++) { | ||
| 5708 | // We can't use FULLTEXT or SPATIAL indexes. | ||
| 5709 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1945150 times.
|
1945155 | if (key->flags & (HA_FULLTEXT | HA_SPATIAL)) continue; |
| 5710 | |||
| 5711 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1945150 times.
|
1945150 | if (key->algorithm == HA_KEY_ALG_HASH) { |
| 5712 | ✗ | if (hton->foreign_keys_flags & HTON_FKS_WITH_SUPPORTING_HASH_KEYS) { | |
| 5713 | /* | ||
| 5714 | Storage engine supports hash keys as supporting keys for foreign | ||
| 5715 | keys. Hash key should contain all foreign key columns and only | ||
| 5716 | them (although in any order). | ||
| 5717 | Example: NDB and unique/primary key with USING HASH clause. | ||
| 5718 | */ | ||
| 5719 | ✗ | if (fk_is_key_exact_match_any_order(alter_info, fk->key_parts, | |
| 5720 | fk_columns_lambda, key)) | ||
| 5721 | ✗ | return key; | |
| 5722 | } | ||
| 5723 | } else { | ||
| 5724 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1945150 times.
|
1945150 | if (hton->foreign_keys_flags & HTON_FKS_WITH_ANY_PREFIX_SUPPORTING_KEYS) { |
| 5725 | /* | ||
| 5726 | Storage engine supports non-hash keys which have common prefix | ||
| 5727 | with the foreign key as supporting keys for it. If there are | ||
| 5728 | several such keys, one which shares biggest prefix with FK is | ||
| 5729 | chosen. | ||
| 5730 | |||
| 5731 | Example: NDB and non-unique keys, or unique/primary keys without | ||
| 5732 | explicit USING HASH clause. | ||
| 5733 | */ | ||
| 5734 | ✗ | uint match_count = fk_key_prefix_match_count( | |
| 5735 | ✗ | alter_info, fk->key_parts, fk_columns_lambda, key, nullptr); | |
| 5736 | |||
| 5737 | ✗ | if (match_count > best_match_count) { | |
| 5738 | ✗ | best_match_count = match_count; | |
| 5739 | ✗ | best_match_key = key; | |
| 5740 | } | ||
| 5741 | } else { | ||
| 5742 | /* | ||
| 5743 | Default case. Storage engine supports non-hash keys which contain | ||
| 5744 | full foreign key as prefix as supporting key for it. | ||
| 5745 | Example: InnoDB. | ||
| 5746 | |||
| 5747 | SQL-layer tries to automatically create such generated key when | ||
| 5748 | foreign key is created. | ||
| 5749 | */ | ||
| 5750 |
3/4✓ Branch 0 taken 1945150 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 613039 times.
✓ Branch 3 taken 1332111 times.
|
1945150 | if (fk_key_is_full_prefix_match(alter_info, fk->key_parts, |
| 5751 | fk_columns_lambda, key, nullptr)) | ||
| 5752 | 613039 | return key; | |
| 5753 | } | ||
| 5754 | } | ||
| 5755 | } | ||
| 5756 | 15 | return best_match_key; | |
| 5757 | } | ||
| 5758 | |||
| 5759 | /** | ||
| 5760 | Make old table definition's foreign keys use temporary names. | ||
| 5761 | This is needed to avoid problems with duplicate foreign key | ||
| 5762 | names while we have two definitions of the same table. | ||
| 5763 | |||
| 5764 | @param thd Thread context. | ||
| 5765 | @param db_name Database where old table definition resides. | ||
| 5766 | @param backup_name Temporary name assigned to old table definition | ||
| 5767 | during ALTER TABLE. | ||
| 5768 | |||
| 5769 | @returns False - Success, True - Failure. | ||
| 5770 | */ | ||
| 5771 | |||
| 5772 | 48 | static bool adjust_foreign_key_names_for_old_table_version( | |
| 5773 | THD *thd, const char *db_name, const char *backup_name) { | ||
| 5774 | 48 | dd::Table *table_def = nullptr; | |
| 5775 |
1/2✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
|
48 | MDL_request_list mdl_requests; |
| 5776 | |||
| 5777 |
4/8✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 48 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 48 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 48 times.
|
48 | if (thd->dd_client()->acquire_for_modification(db_name, backup_name, |
| 5778 | &table_def)) | ||
| 5779 | ✗ | return true; | |
| 5780 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
|
48 | assert(table_def != nullptr); |
| 5781 | |||
| 5782 |
6/10✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 48 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 48 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 57 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 57 times.
✓ Branch 9 taken 48 times.
|
105 | for (dd::Foreign_key *fk : *table_def->foreign_keys()) { |
| 5783 | char temp_fk_name[4 + 20 + 1]; | ||
| 5784 | |||
| 5785 | 114 | snprintf(temp_fk_name, sizeof(temp_fk_name), "#fk_%llu", | |
| 5786 |
1/2✓ Branch 0 taken 57 times.
✗ Branch 1 not taken.
|
57 | (ulonglong)fk->id()); |
| 5787 | |||
| 5788 | /* | ||
| 5789 | Acquire metadata locks on temporary names before updating data-dictionary | ||
| 5790 | just in case somebody tries to create foreign keys with names like | ||
| 5791 | #fk_<number> concurrently. | ||
| 5792 | */ | ||
| 5793 |
1/2✓ Branch 0 taken 57 times.
✗ Branch 1 not taken.
|
57 | MDL_request *mdl_request = new (thd->mem_root) MDL_request; |
| 5794 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
|
57 | if (mdl_request == nullptr) return true; |
| 5795 |
1/2✓ Branch 0 taken 57 times.
✗ Branch 1 not taken.
|
57 | MDL_REQUEST_INIT(mdl_request, MDL_key::FOREIGN_KEY, db_name, temp_fk_name, |
| 5796 | MDL_EXCLUSIVE, MDL_STATEMENT); | ||
| 5797 |
1/2✓ Branch 0 taken 57 times.
✗ Branch 1 not taken.
|
57 | mdl_requests.push_front(mdl_request); |
| 5798 | |||
| 5799 | // Update dd::Foreign_key object but do not store it in data-dictionary yet. | ||
| 5800 |
2/4✓ Branch 0 taken 57 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 57 times.
✗ Branch 3 not taken.
|
57 | fk->set_name(temp_fk_name); |
| 5801 | } | ||
| 5802 | |||
| 5803 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
|
48 | assert(!mdl_requests.is_empty()); |
| 5804 | |||
| 5805 |
2/4✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 48 times.
|
48 | if (thd->mdl_context.acquire_locks(&mdl_requests, |
| 5806 | thd->variables.lock_wait_timeout)) | ||
| 5807 | ✗ | return true; | |
| 5808 | |||
| 5809 |
1/2✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
|
48 | return thd->dd_client()->update(table_def); |
| 5810 | } | ||
| 5811 | |||
| 5812 | /** | ||
| 5813 | Find max value of number component among existing generated foreign | ||
| 5814 | key names for the table. | ||
| 5815 | |||
| 5816 | @param table_name Table name (should be already in lowercase | ||
| 5817 | if l_c_t_n > 0). | ||
| 5818 | @param table_def Table definition. | ||
| 5819 | @param hton Table storage engine. | ||
| 5820 | |||
| 5821 | @note We assume that generated names follow pattern: | ||
| 5822 | (table name)(SE-specific or default FK name suffix)(number) | ||
| 5823 | E.g. "table_name_ibfk_####" for InnoDB. This function is in sync | ||
| 5824 | with generate_fk_name() and dd::rename_foreign_keys(). | ||
| 5825 | |||
| 5826 | @note This function mimics dict_table_get_highest_foreign_id() from 5.7. | ||
| 5827 | */ | ||
| 5828 | |||
| 5829 | 145969 | static uint get_fk_max_generated_name_number(const char *table_name, | |
| 5830 | const dd::Table *table_def, | ||
| 5831 | handlerton *hton) { | ||
| 5832 | 145969 | uint key_number = 0; | |
| 5833 | /* | ||
| 5834 | There is no need to lowercase table_name as it is already supposed | ||
| 5835 | to be in lowercase. | ||
| 5836 | */ | ||
| 5837 | 145969 | size_t table_name_length = strlen(table_name); | |
| 5838 | |||
| 5839 | 145969 | const LEX_CSTRING &fk_name_suffix = | |
| 5840 |
2/2✓ Branch 0 taken 129315 times.
✓ Branch 1 taken 16654 times.
|
145969 | hton->fk_name_suffix.str ? hton->fk_name_suffix : FK_NAME_DEFAULT_SUFFIX; |
| 5841 | |||
| 5842 |
6/10✓ Branch 0 taken 145969 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 145969 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 145969 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 642 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 642 times.
✓ Branch 9 taken 145969 times.
|
146611 | for (const dd::Foreign_key *fk : table_def->foreign_keys()) { |
| 5843 | /* | ||
| 5844 | We assume that the name is generated if it starts with: | ||
| 5845 | <table_name><SE-specific or default FK name suffix> | ||
| 5846 | |||
| 5847 | Note that unlike during RENAME TABLE handling, here, i.e. when | ||
| 5848 | generating name for new constraints, we mimic InnoDB's behavior from | ||
| 5849 | 5.7 and ignore pre-existing generated names which have pre-4.0.18 format. | ||
| 5850 | */ | ||
| 5851 |
1/2✓ Branch 0 taken 642 times.
✗ Branch 1 not taken.
|
642 | if (dd::is_generated_foreign_key_name(table_name, table_name_length, hton, |
| 5852 |
4/4✓ Branch 0 taken 233 times.
✓ Branch 1 taken 409 times.
✓ Branch 2 taken 229 times.
✓ Branch 3 taken 413 times.
|
875 | *fk) && |
| 5853 |
3/4✓ Branch 0 taken 233 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 229 times.
✓ Branch 3 taken 4 times.
|
233 | (fk->name().c_str()[table_name_length + fk_name_suffix.length] != |
| 5854 | '0')) { | ||
| 5855 | 229 | char *end = nullptr; | |
| 5856 | 229 | uint nr = my_strtoull( | |
| 5857 |
1/2✓ Branch 0 taken 229 times.
✗ Branch 1 not taken.
|
229 | fk->name().c_str() + table_name_length + fk_name_suffix.length, &end, |
| 5858 | 229 | 10); | |
| 5859 |
2/4✓ Branch 0 taken 229 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 229 times.
✗ Branch 3 not taken.
|
229 | if (!*end && nr > key_number) key_number = nr; |
| 5860 | } | ||
| 5861 | } | ||
| 5862 | 145969 | return key_number; | |
| 5863 | } | ||
| 5864 | |||
| 5865 | /** | ||
| 5866 | Generate a foreign key name and store it in buffer provided. | ||
| 5867 | |||
| 5868 | @note Foreign key names have to be unique for a given schema. | ||
| 5869 | This function is used when the user has not specified | ||
| 5870 | neither constraint name nor foreign key name. | ||
| 5871 | |||
| 5872 | @note We generated names according to the pattern: | ||
| 5873 | (table name)(SE-specific or default FK name suffix)(counter) | ||
| 5874 | The counter is 1-based and per table. The number chosen for the | ||
| 5875 | counter is 1 higher than the highest number currently in use. | ||
| 5876 | For InnoDB "_ibfk_" is used as suffix, so names are compatible | ||
| 5877 | with names generated by InnoDB in 5.7. For NDB, suffix "_fk_" | ||
| 5878 | is used and compatibility is not preserved (as in 5.7 NDB | ||
| 5879 | uses radically different approach anyway). | ||
| 5880 | |||
| 5881 | @param name_buff Buffer for generated name. | ||
| 5882 | @param name_buff_size Size of name buffer, if buffer | ||
| 5883 | is too small generated name | ||
| 5884 | will be truncated. | ||
| 5885 | @param table_name Table name. | ||
| 5886 | @param hton Table storage engine. | ||
| 5887 | @param[in,out] fk_max_generated_name_number Max value of number component | ||
| 5888 | among existing generated | ||
| 5889 | foreign key names. | ||
| 5890 | */ | ||
| 5891 | |||
| 5892 | 1224275 | static void generate_fk_name(char *name_buff, size_t name_buff_size, | |
| 5893 | const char *table_name, handlerton *hton, | ||
| 5894 | uint *fk_max_generated_name_number) { | ||
| 5895 | 1224275 | snprintf(name_buff, name_buff_size, "%s%s%u", table_name, | |
| 5896 | 1224275 | (hton->fk_name_suffix.str ? hton->fk_name_suffix.str | |
| 5897 | : FK_NAME_DEFAULT_SUFFIX.str), | ||
| 5898 |
2/2✓ Branch 0 taken 1224267 times.
✓ Branch 1 taken 8 times.
|
1224275 | ++*fk_max_generated_name_number); |
| 5899 | 1224275 | } | |
| 5900 | |||
| 5901 | /** | ||
| 5902 | Generate a foreign key name, allocate memory from thread's current | ||
| 5903 | memory root for it. | ||
| 5904 | |||
| 5905 | @note Foreign key names have to be unique for a given schema. | ||
| 5906 | This function is used when the user has not specified | ||
| 5907 | neither constraint name nor foreign key name. | ||
| 5908 | |||
| 5909 | @note We generated names according to the pattern: | ||
| 5910 | (table name)(SE-specific or default FK name suffix)(counter) | ||
| 5911 | The counter is 1-based and per table. The number chosen for the | ||
| 5912 | counter is 1 higher than the highest number currently in use. | ||
| 5913 | For InnoDB "_ibfk_" is used as suffix, so names are compatible | ||
| 5914 | with names generated by InnoDB in 5.7. For NDB, suffix "_fk_" | ||
| 5915 | is used and compatibility is not preserved (as in 5.7 NDB | ||
| 5916 | uses radically different approach anyway). | ||
| 5917 | |||
| 5918 | @param table_name Table name. | ||
| 5919 | @param hton Table storage engine. | ||
| 5920 | @param[in,out] fk_max_generated_name_number Max value of number component | ||
| 5921 | among existing generated foreign | ||
| 5922 | key names. | ||
| 5923 | |||
| 5924 | @retval Generated name | ||
| 5925 | */ | ||
| 5926 | |||
| 5927 | 612137 | static const char *generate_fk_name(const char *table_name, handlerton *hton, | |
| 5928 | uint *fk_max_generated_name_number) { | ||
| 5929 | // The below buffer should be sufficient for any generated name. | ||
| 5930 | char name[NAME_LEN + MAX_FK_NAME_SUFFIX_LENGTH + 10 + 1]; | ||
| 5931 | 612137 | generate_fk_name(name, sizeof(name), table_name, hton, | |
| 5932 | fk_max_generated_name_number); | ||
| 5933 |
1/2✓ Branch 0 taken 612137 times.
✗ Branch 1 not taken.
|
1224274 | return sql_strdup(name); |
| 5934 | } | ||
| 5935 | |||
| 5936 | /** | ||
| 5937 | Check if candidate parent/supporting key contains exactly the same | ||
| 5938 | columns as the foreign key, possibly, in different order. Also check | ||
| 5939 | that columns usage by key is acceptable, i.e. key is not over column | ||
| 5940 | prefix. | ||
| 5941 | |||
| 5942 | @tparam F Function class which returns foreign key's | ||
| 5943 | referenced or referencing (depending on whether | ||
| 5944 | we check candidate parent or supporting key) | ||
| 5945 | column name by its index. | ||
| 5946 | @param fk_col_count Number of columns in the foreign key. | ||
| 5947 | @param fk_columns Object of F type bound to the specific foreign key | ||
| 5948 | for which parent/supporting key check is carried | ||
| 5949 | out. | ||
| 5950 | @param idx dd::Index object describing candidate parent/ | ||
| 5951 | supporting key. | ||
| 5952 | |||
| 5953 | @sa fk_is_key_exact_match_any_order(Alter_info, uint, F, KEY). | ||
| 5954 | |||
| 5955 | @retval True - Key is proper parent/supporting key for the foreign key. | ||
| 5956 | @retval False - Key can't be parent/supporting key for the foreign key. | ||
| 5957 | */ | ||
| 5958 | template <class F> | ||
| 5959 | ✗ | static bool fk_is_key_exact_match_any_order(uint fk_col_count, | |
| 5960 | const F &fk_columns, | ||
| 5961 | const dd::Index *idx) { | ||
| 5962 | /* | ||
| 5963 | Skip keys which have less elements (including hidden ones) | ||
| 5964 | than foreign key right away. | ||
| 5965 | */ | ||
| 5966 | ✗ | if (fk_col_count > idx->elements().size()) return false; | |
| 5967 | |||
| 5968 | ✗ | uint col_matched = 0; | |
| 5969 | |||
| 5970 | ✗ | for (const dd::Index_element *idx_el : idx->elements()) { | |
| 5971 | ✗ | if (idx_el->is_hidden()) continue; | |
| 5972 | |||
| 5973 | ✗ | uint j = 0; | |
| 5974 | ✗ | while (j < fk_col_count) { | |
| 5975 | ✗ | if (my_strcasecmp(system_charset_info, idx_el->column().name().c_str(), | |
| 5976 | ✗ | fk_columns(j)) == 0) | |
| 5977 | ✗ | break; | |
| 5978 | ✗ | j++; | |
| 5979 | } | ||
| 5980 | ✗ | if (j == fk_col_count) return false; | |
| 5981 | |||
| 5982 | /* | ||
| 5983 | Foreign keys over virtual columns are not allowed. | ||
| 5984 | This is checked at earlier stage. | ||
| 5985 | */ | ||
| 5986 | ✗ | assert(!idx_el->column().is_virtual()); | |
| 5987 | |||
| 5988 | /* | ||
| 5989 | Prefix keys are not allowed/considered non-matching. | ||
| 5990 | |||
| 5991 | There is a special provision which allows to treat unique keys on | ||
| 5992 | POINT and BLOB columns with prefix length equal to real column | ||
| 5993 | length as candidate/primary keys. However, since InnoDB doesn't | ||
| 5994 | allow columns of such types in FKs, we don't need similar provision | ||
| 5995 | here. So we can simply use dd::Index_element::is_prefix(). | ||
| 5996 | |||
| 5997 | Calling Index_element::is_prefix() can be a bit expensive so | ||
| 5998 | we do this after checking if foreign key has matching column | ||
| 5999 | (foreign key column list is likely to be small). | ||
| 6000 | */ | ||
| 6001 | ✗ | if (idx_el->is_prefix()) return false; | |
| 6002 | |||
| 6003 | ✗ | ++col_matched; | |
| 6004 | } | ||
| 6005 | |||
| 6006 | ✗ | return (col_matched == fk_col_count); | |
| 6007 | } | ||
| 6008 | |||
| 6009 | /** | ||
| 6010 | Count how many elements from the start of the candidate parent/supporting | ||
| 6011 | key match elements at the start of the foreign key (prefix parts are | ||
| 6012 | considered non-matching). | ||
| 6013 | |||
| 6014 | @tparam F Function class which returns foreign key's | ||
| 6015 | referenced or referencing (depending on whether | ||
| 6016 | we check candidate parent or supporting key) | ||
| 6017 | column name by its index. | ||
| 6018 | @param fk_col_count Number of columns in the foreign key. | ||
| 6019 | @param fk_columns Object of F type bound to the specific foreign key | ||
| 6020 | for which parent/supporting key check is carried | ||
| 6021 | out. | ||
| 6022 | @param idx dd::Index object describing candidate parent/ | ||
| 6023 | supporting key. | ||
| 6024 | @param use_hidden Use hidden elements of the key as well. | ||
| 6025 | |||
| 6026 | @sa fk_key_prefix_match_count(Alter_info, uint, F, KEY, KEY). | ||
| 6027 | |||
| 6028 | @retval Number of matching columns. | ||
| 6029 | */ | ||
| 6030 | template <class F> | ||
| 6031 | 653608 | static uint fk_key_prefix_match_count(uint fk_col_count, const F &fk_columns, | |
| 6032 | const dd::Index *idx, bool use_hidden) { | ||
| 6033 | 653608 | uint fk_col_idx = 0; | |
| 6034 | |||
| 6035 |
6/10✓ Branch 0 taken 326804 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 326804 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 326804 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 653789 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 653789 times.
✓ Branch 9 taken 62 times.
|
1961310 | for (const dd::Index_element *idx_el : idx->elements()) { |
| 6036 |
2/2✓ Branch 0 taken 326444 times.
✓ Branch 1 taken 327345 times.
|
1307578 | if (fk_col_idx == fk_col_count) break; |
| 6037 | |||
| 6038 |
5/8✓ Branch 0 taken 108 times.
✓ Branch 1 taken 327237 times.
✓ Branch 2 taken 108 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 108 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 327345 times.
|
654690 | if (!use_hidden && idx_el->is_hidden()) continue; |
| 6039 | |||
| 6040 |
7/12✓ Branch 0 taken 1548 times.
✓ Branch 1 taken 325797 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1548 times.
✓ Branch 4 taken 325797 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1548 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 325797 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1548 times.
✗ Branch 11 not taken.
|
654690 | if (my_strcasecmp(system_charset_info, idx_el->column().name().c_str(), |
| 6041 |
2/2✓ Branch 0 taken 298 times.
✓ Branch 1 taken 327047 times.
|
654690 | fk_columns(fk_col_idx)) != 0) |
| 6042 | 596 | break; | |
| 6043 | |||
| 6044 | /* | ||
| 6045 | Foreign keys over virtual columns are not allowed. | ||
| 6046 | This is checked at earlier stage. | ||
| 6047 | */ | ||
| 6048 |
3/6✓ Branch 0 taken 327047 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 327047 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 327047 times.
|
654094 | assert(!idx_el->column().is_virtual()); |
| 6049 | |||
| 6050 | /* | ||
| 6051 | Prefix parts are considered non-matching. | ||
| 6052 | |||
| 6053 | There is a special provision which allows to treat unique keys on | ||
| 6054 | POINT and BLOB columns with prefix length equal to real column | ||
| 6055 | length as candidate/primary keys. However, since InnoDB doesn't | ||
| 6056 | allow columns of such types in FKs, we don't need similar provision | ||
| 6057 | here. So we can simply use dd::Index_element::is_prefix(). | ||
| 6058 | |||
| 6059 | Calling Index_element::is_prefix() can be a bit expensive so | ||
| 6060 | we do this after checking column name. | ||
| 6061 | |||
| 6062 | InnoDB doesn't set correct length for hidden index elements so | ||
| 6063 | we simply assume that they use the full columns. We avoid calling | ||
| 6064 | this code when it is not correct, see find_fk_parent_key(). | ||
| 6065 | */ | ||
| 6066 |
6/10✓ Branch 0 taken 327047 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 326997 times.
✓ Branch 3 taken 50 times.
✓ Branch 4 taken 326997 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 326997 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 327047 times.
|
654094 | if (!idx_el->is_hidden() && idx_el->is_prefix()) break; |
| 6067 | |||
| 6068 | 654094 | ++fk_col_idx; | |
| 6069 | } | ||
| 6070 | |||
| 6071 | 653608 | return fk_col_idx; | |
| 6072 | } | ||
| 6073 | |||
| 6074 | /** | ||
| 6075 | Check if candidate parent/supporting key contains all columns from the | ||
| 6076 | foreign key at its start and in the same order it is in the foreign key. | ||
| 6077 | Also check that columns usage by key is acceptable, i.e. key is not over | ||
| 6078 | column prefix. | ||
| 6079 | |||
| 6080 | @tparam F Function class which returns foreign key's | ||
| 6081 | referenced or referencing (depending on whether | ||
| 6082 | we check candidate parent or supporting key) | ||
| 6083 | column name by its index. | ||
| 6084 | @param fk_col_count Number of columns in the foreign key. | ||
| 6085 | @param fk_columns Object of F type bound to the specific foreign key | ||
| 6086 | for which parent/supporting key check is carried | ||
| 6087 | out. | ||
| 6088 | @param idx dd::Index object describing candidate parent/ | ||
| 6089 | supporting key. | ||
| 6090 | @param use_hidden Use hidden elements of the key as well. | ||
| 6091 | |||
| 6092 | @sa fk_key_is_full_prefix_match(Alter_info, uint, F, KEY, KEY). | ||
| 6093 | |||
| 6094 | @retval True - Key is proper parent/supporting key for the foreign key. | ||
| 6095 | @retval False - Key can't be parent/supporting key for the foreign key. | ||
| 6096 | */ | ||
| 6097 | template <class F> | ||
| 6098 | 653608 | static bool fk_key_is_full_prefix_match(uint fk_col_count, const F &fk_columns, | |
| 6099 | const dd::Index *idx, bool use_hidden) { | ||
| 6100 | // The index must have at least same amount of elements as the foreign key. | ||
| 6101 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 326804 times.
|
653608 | if (fk_col_count > idx->elements().size()) return false; |
| 6102 | |||
| 6103 | uint match_count = | ||
| 6104 | 653608 | fk_key_prefix_match_count(fk_col_count, fk_columns, idx, use_hidden); | |
| 6105 | |||
| 6106 | 653608 | return (match_count == fk_col_count); | |
| 6107 | } | ||
| 6108 | |||
| 6109 | /** | ||
| 6110 | Find parent key which matches the foreign key. Prefer unique key if possible. | ||
| 6111 | |||
| 6112 | @tparam F Function class which returns foreign key's column | ||
| 6113 | name by its index. | ||
| 6114 | @param hton Handlerton for tables' storage engine. Used to | ||
| 6115 | figure out what kind of parent keys are supported | ||
| 6116 | by the storage engine.. | ||
| 6117 | @param supporting_key Supporting key of the child. Needed to skip | ||
| 6118 | supporting keys as candidate parent keys for | ||
| 6119 | self referencing FKs. | ||
| 6120 | @param parent_table_def dd::Table object describing the parent table. | ||
| 6121 | @param fk_col_count Number of columns in the foreign key. | ||
| 6122 | @param fk_columns Object of F type bound to the specific foreign key | ||
| 6123 | for which parent key check is carried out. | ||
| 6124 | |||
| 6125 | @retval non-nullptr - pointer to dd::Index object describing the parent key. | ||
| 6126 | @retval nullptr - if no parent key were found. | ||
| 6127 | */ | ||
| 6128 | template <class F> | ||
| 6129 | 652980 | static const dd::Index *find_fk_parent_key(handlerton *hton, | |
| 6130 | const dd::Index *supporting_key, | ||
| 6131 | const dd::Table *parent_table_def, | ||
| 6132 | uint fk_col_count, | ||
| 6133 | const F &fk_columns) { | ||
| 6134 | 652980 | bool use_hidden = false; | |
| 6135 | |||
| 6136 |
1/2✓ Branch 0 taken 326490 times.
✗ Branch 1 not taken.
|
652980 | if (hton->foreign_keys_flags & HTON_FKS_WITH_EXTENDED_PARENT_KEYS) { |
| 6137 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 326490 times.
|
652980 | assert(hton->foreign_keys_flags & HTON_FKS_WITH_PREFIX_PARENT_KEYS); |
| 6138 | /* | ||
| 6139 | Engine considers hidden part of key (columns from primary key | ||
| 6140 | which are implicitly added to secondary keys) when determines | ||
| 6141 | if it can serve as parent. Example: InnoDB. | ||
| 6142 | |||
| 6143 | Note that InnoDB doesn't correctly set length of these hidden | ||
| 6144 | elements of keys, so we assume that they always cover the whole | ||
| 6145 | column. To be able to do this we need to exclude primary keys | ||
| 6146 | with prefix elements [sic!] from consideration. This means that | ||
| 6147 | we won't support some exotic parent key scenarios which were | ||
| 6148 | supported in 5.7. For example: | ||
| 6149 | |||
| 6150 | CREATE TABLE t1 (a INT, b CHAR(100), c int, KEY(c), | ||
| 6151 | PRIMARY KEY (a, b(10))); | ||
| 6152 | CREATE TABLE t2 (fk1 int, fk2 int, | ||
| 6153 | FOREIGN KEY (fk1, fk2) REFERENCES t1 (c, a)); | ||
| 6154 | */ | ||
| 6155 | dd::Table::Index_collection::const_iterator first_idx_it = | ||
| 6156 |
3/6✓ Branch 0 taken 326490 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 326490 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 326490 times.
✗ Branch 5 not taken.
|
652980 | std::find_if(parent_table_def->indexes().cbegin(), |
| 6157 |
2/4✓ Branch 0 taken 326490 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 326490 times.
✗ Branch 3 not taken.
|
652980 | parent_table_def->indexes().cend(), |
| 6158 | 326561 | [](const dd::Index *i) { return !i->is_hidden(); }); | |
| 6159 | |||
| 6160 |
4/6✓ Branch 0 taken 326490 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 326490 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 326484 times.
✓ Branch 5 taken 6 times.
|
652980 | if (first_idx_it != parent_table_def->indexes().cend()) { |
| 6161 | /* | ||
| 6162 | Unlike similar check in prepare_self_ref_fk_parent_key() call | ||
| 6163 | to dd::Index::is_candidate_key() is not cheap, so we try to | ||
| 6164 | avoid it unless absolutely necessary. As result we try to use | ||
| 6165 | hidden columns even for tables without implicit primary key, | ||
| 6166 | which works fine (since such tables won't have any hidden | ||
| 6167 | columns matching foreign key columns). | ||
| 6168 | */ | ||
| 6169 |
5/8✓ Branch 0 taken 326484 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 326484 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 326375 times.
✓ Branch 5 taken 109 times.
✓ Branch 6 taken 326484 times.
✗ Branch 7 not taken.
|
1305718 | if ((*first_idx_it)->type() != dd::Index::IT_PRIMARY || |
| 6170 |
3/6✓ Branch 0 taken 326375 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 326375 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 326375 times.
✗ Branch 5 not taken.
|
652750 | (*first_idx_it)->is_candidate_key()) |
| 6171 | 652968 | use_hidden = true; | |
| 6172 | } | ||
| 6173 | } | ||
| 6174 | |||
| 6175 |
6/10✓ Branch 0 taken 326490 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 326490 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 326490 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 326793 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 326793 times.
✓ Branch 9 taken 20 times.
|
1306606 | for (const dd::Index *idx : parent_table_def->indexes()) { |
| 6176 | // We can't use FULLTEXT or SPATIAL indexes. | ||
| 6177 |
3/6✓ Branch 0 taken 326793 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 326793 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 326793 times.
|
1307172 | if (idx->type() == dd::Index::IT_FULLTEXT || |
| 6178 |
2/4✓ Branch 0 taken 326793 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 326793 times.
|
653586 | idx->type() == dd::Index::IT_SPATIAL) |
| 6179 | ✗ | continue; | |
| 6180 | |||
| 6181 |
1/2✓ Branch 0 taken 326793 times.
✗ Branch 1 not taken.
|
653586 | if (hton->foreign_keys_flags & |
| 6182 | HTON_FKS_NEED_DIFFERENT_PARENT_AND_SUPPORTING_KEYS) { | ||
| 6183 | /* | ||
| 6184 | The storage engine does not support using the same index for both the | ||
| 6185 | supporting index and the parent index. In this case, the supporting | ||
| 6186 | index cannot be a candidate parent index, and must be skipped. | ||
| 6187 | */ | ||
| 6188 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 326793 times.
|
653586 | if (idx == supporting_key) continue; |
| 6189 | } | ||
| 6190 | |||
| 6191 | // We also can't use hidden indexes. | ||
| 6192 |
3/4✓ Branch 0 taken 326793 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 77 times.
✓ Branch 3 taken 326716 times.
|
653586 | if (idx->is_hidden()) continue; |
| 6193 | |||
| 6194 |
1/2✓ Branch 0 taken 326716 times.
✗ Branch 1 not taken.
|
653432 | if (hton->foreign_keys_flags & HTON_FKS_WITH_PREFIX_PARENT_KEYS) { |
| 6195 | /* | ||
| 6196 | Engine supports unique and non unique-parent keys which contain full | ||
| 6197 | foreign key as its prefix. Example: InnoDB. | ||
| 6198 | |||
| 6199 | Primary and unique keys are sorted before non-unique keys. | ||
| 6200 | So if there is suitable unique parent key we will always find | ||
| 6201 | it before any non-unique key. | ||
| 6202 | */ | ||
| 6203 | |||
| 6204 |
3/4✓ Branch 0 taken 326716 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 326470 times.
✓ Branch 3 taken 246 times.
|
653432 | if (fk_key_is_full_prefix_match(fk_col_count, fk_columns, idx, |
| 6205 | use_hidden)) | ||
| 6206 | 652940 | return idx; | |
| 6207 | } else { | ||
| 6208 | /* | ||
| 6209 | Default case. Engine only supports unique parent keys which | ||
| 6210 | contain exactly the same columns as foreign key, possibly | ||
| 6211 | in different order. Example: NDB. | ||
| 6212 | */ | ||
| 6213 | ✗ | if ((idx->type() == dd::Index::IT_PRIMARY || | |
| 6214 | ✗ | idx->type() == dd::Index::IT_UNIQUE) && | |
| 6215 | ✗ | fk_is_key_exact_match_any_order(fk_col_count, fk_columns, idx)) | |
| 6216 | ✗ | return idx; | |
| 6217 | } | ||
| 6218 | } | ||
| 6219 | 40 | return nullptr; | |
| 6220 | } | ||
| 6221 | |||
| 6222 | /** | ||
| 6223 | Find supporting key for the foreign key. | ||
| 6224 | |||
| 6225 | @param hton Handlerton for tables' storage engine. Used to | ||
| 6226 | figure out what kind of supporting keys are | ||
| 6227 | allowed by the storage engine. | ||
| 6228 | @param table_def dd::Table object describing the child table. | ||
| 6229 | @param fk dd::Foreign_key object describing the foreign | ||
| 6230 | key. | ||
| 6231 | |||
| 6232 | @sa find_fk_supporting_key(handlerton*, Alter_info*, const KEY*, uint, | ||
| 6233 | const FOREIGN_KEY*) | ||
| 6234 | |||
| 6235 | @retval non-nullptr - pointer to dd::Index object describing supporting key. | ||
| 6236 | @retval nullptr - if no supporting key were found. | ||
| 6237 | */ | ||
| 6238 | 36 | static const dd::Index *find_fk_supporting_key(handlerton *hton, | |
| 6239 | const dd::Table *table_def, | ||
| 6240 | const dd::Foreign_key *fk) { | ||
| 6241 | 36 | uint best_match_count = 0; | |
| 6242 | 36 | const dd::Index *best_match_idx = nullptr; | |
| 6243 | |||
| 6244 | 108 | auto fk_columns_lambda = [fk](uint i) { | |
| 6245 | 108 | return fk->elements()[i]->column().name().c_str(); | |
| 6246 | 36 | }; | |
| 6247 | |||
| 6248 |
5/10✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 36 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 36 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 96 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 96 times.
✗ Branch 9 not taken.
|
96 | for (const dd::Index *idx : table_def->indexes()) { |
| 6249 | // We can't use FULLTEXT or SPATIAL indexes. | ||
| 6250 |
4/6✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 96 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 95 times.
|
192 | if (idx->type() == dd::Index::IT_FULLTEXT || |
| 6251 |
3/4✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 95 times.
|
96 | idx->type() == dd::Index::IT_SPATIAL) |
| 6252 | 1 | continue; | |
| 6253 | |||
| 6254 | // We also can't use hidden indexes. | ||
| 6255 |
3/4✓ Branch 0 taken 95 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 88 times.
|
95 | if (idx->is_hidden()) continue; |
| 6256 | |||
| 6257 |
2/4✓ Branch 0 taken 88 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 88 times.
|
88 | if (idx->algorithm() == dd::Index::IA_HASH) { |
| 6258 | ✗ | if (hton->foreign_keys_flags & HTON_FKS_WITH_SUPPORTING_HASH_KEYS) { | |
| 6259 | /* | ||
| 6260 | Storage engine supports hash keys as supporting keys for foreign | ||
| 6261 | keys. Hash key should contain all foreign key columns and only | ||
| 6262 | them (although in any order). | ||
| 6263 | Example: NDB and unique/primary key with USING HASH clause. | ||
| 6264 | */ | ||
| 6265 | ✗ | if (fk_is_key_exact_match_any_order(fk->elements().size(), | |
| 6266 | fk_columns_lambda, idx)) | ||
| 6267 | 36 | return idx; | |
| 6268 | } | ||
| 6269 | } else { | ||
| 6270 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 88 times.
|
88 | if (hton->foreign_keys_flags & HTON_FKS_WITH_ANY_PREFIX_SUPPORTING_KEYS) { |
| 6271 | /* | ||
| 6272 | Storage engine supports non-hash keys which have common prefix | ||
| 6273 | with the foreign key as supporting keys for it. If there are | ||
| 6274 | several such keys, one which shares biggest prefix with FK is | ||
| 6275 | chosen. | ||
| 6276 | |||
| 6277 | Example: NDB and non-unique keys, or unique/primary keys without | ||
| 6278 | explicit USING HASH clause. | ||
| 6279 | */ | ||
| 6280 | ✗ | uint match_count = fk_key_prefix_match_count( | |
| 6281 | ✗ | fk->elements().size(), fk_columns_lambda, idx, false); | |
| 6282 | |||
| 6283 | ✗ | if (match_count > best_match_count) { | |
| 6284 | ✗ | best_match_count = match_count; | |
| 6285 | ✗ | best_match_idx = idx; | |
| 6286 | } | ||
| 6287 | } else { | ||
| 6288 | /* | ||
| 6289 | Default case. Storage engine supports non-hash keys which contain | ||
| 6290 | full foreign key as prefix as supporting key for it. | ||
| 6291 | Example: InnoDB. | ||
| 6292 | |||
| 6293 | SQL-layer tries to automatically create such generated key when | ||
| 6294 | foreign key is created. | ||
| 6295 | */ | ||
| 6296 |
4/6✓ Branch 0 taken 88 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 88 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 36 times.
✓ Branch 5 taken 52 times.
|
88 | if (fk_key_is_full_prefix_match(fk->elements().size(), |
| 6297 | fk_columns_lambda, idx, false)) | ||
| 6298 | 36 | return idx; | |
| 6299 | } | ||
| 6300 | } | ||
| 6301 | } | ||
| 6302 | ✗ | return best_match_idx; | |
| 6303 | } | ||
| 6304 | |||
| 6305 | /* | ||
| 6306 | Check if parent key for foreign key exists, set foreign key's unique | ||
| 6307 | constraint name accordingly. Emit error if no parent key found. | ||
| 6308 | |||
| 6309 | @note Prefer unique key if possible. If parent key is non-unique | ||
| 6310 | unique constraint name is set to NULL. | ||
| 6311 | |||
| 6312 | @note CREATE TABLE and ALTER TABLE code use this function for | ||
| 6313 | non-self-referencing foreign keys. | ||
| 6314 | |||
| 6315 | @sa prepare_fk_parent_key(handlerton, dd::Table, dd::Table, dd::Table, | ||
| 6316 | dd::Foreign_key) | ||
| 6317 | |||
| 6318 | @param hton Handlerton for tables' storage engine. | ||
| 6319 | @param parent_table_def dd::Table object describing parent table. | ||
| 6320 | @param fk[in,out] FOREIGN_KEY object describing the FK, its | ||
| 6321 | unique_index_name member will be updated | ||
| 6322 | if matching unique constraint is found. | ||
| 6323 | |||
| 6324 | @retval Operation result. False if success. | ||
| 6325 | */ | ||
| 6326 | 325232 | static bool prepare_fk_parent_key(handlerton *hton, | |
| 6327 | const dd::Table *parent_table_def, | ||
| 6328 | FOREIGN_KEY *fk) { | ||
| 6329 | 325797 | auto fk_columns_lambda = [fk](uint i) { return fk->fk_key_part[i].str; }; | |
| 6330 | |||
| 6331 | /* | ||
| 6332 | Here, it is safe to pass nullptr as supporting key, since this | ||
| 6333 | function is not called for self referencing foreign keys. | ||
| 6334 | */ | ||
| 6335 |
1/2✓ Branch 0 taken 325232 times.
✗ Branch 1 not taken.
|
325232 | const dd::Index *parent_key = find_fk_parent_key( |
| 6336 | hton, nullptr, parent_table_def, fk->key_parts, fk_columns_lambda); | ||
| 6337 | |||
| 6338 |
2/2✓ Branch 0 taken 325220 times.
✓ Branch 1 taken 12 times.
|
325232 | if (parent_key != nullptr) { |
| 6339 | /* | ||
| 6340 | We only store names of PRIMARY/UNIQUE keys in unique_index_name, | ||
| 6341 | even though InnoDB allows non-unique indexes as parent keys. | ||
| 6342 | */ | ||
| 6343 |
5/6✓ Branch 0 taken 325220 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 152 times.
✓ Branch 3 taken 325068 times.
✓ Branch 4 taken 325104 times.
✓ Branch 5 taken 116 times.
|
325372 | if (parent_key->type() == dd::Index::IT_PRIMARY || |
| 6344 |
3/4✓ Branch 0 taken 152 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 36 times.
✓ Branch 3 taken 116 times.
|
152 | parent_key->type() == dd::Index::IT_UNIQUE) { |
| 6345 |
1/2✓ Branch 0 taken 325104 times.
✗ Branch 1 not taken.
|
325104 | fk->unique_index_name = parent_key->name().c_str(); |
| 6346 | } else { | ||
| 6347 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 116 times.
|
116 | assert(fk->unique_index_name == nullptr); |
| 6348 | } | ||
| 6349 | 325220 | return false; | |
| 6350 | } | ||
| 6351 | |||
| 6352 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | my_error(ER_FK_NO_INDEX_PARENT, MYF(0), fk->name, fk->ref_table.str); |
| 6353 | 12 | return true; | |
| 6354 | } | ||
| 6355 | |||
| 6356 | /** | ||
| 6357 | Find parent key which matches the foreign key. Prefer unique key if possible. | ||
| 6358 | |||
| 6359 | @param hton Handlerton for tables' storage engine. | ||
| 6360 | @param supporting_key Supporting key of the child. Needed to skip | ||
| 6361 | supporting keys as candidate parent keys for | ||
| 6362 | self referencing FKs. | ||
| 6363 | @param parent_table_def dd::Table object describing the parent table. | ||
| 6364 | @param fk dd::Foreign_key object describing the foreign key. | ||
| 6365 | |||
| 6366 | @retval non-nullptr - pointer to dd::Index object describing the parent key. | ||
| 6367 | @retval nullptr - if no parent key were found. | ||
| 6368 | */ | ||
| 6369 | 1258 | static const dd::Index *find_fk_parent_key(handlerton *hton, | |
| 6370 | const dd::Index *supporting_key, | ||
| 6371 | const dd::Table *parent_table_def, | ||
| 6372 | const dd::Foreign_key *fk) { | ||
| 6373 | 1440 | auto fk_columns_lambda = [fk](uint i) { | |
| 6374 | 1440 | return fk->elements()[i]->referenced_column_name().c_str(); | |
| 6375 | 1258 | }; | |
| 6376 |
1/2✓ Branch 0 taken 1258 times.
✗ Branch 1 not taken.
|
1258 | return find_fk_parent_key(hton, supporting_key, parent_table_def, |
| 6377 |
1/2✓ Branch 0 taken 1258 times.
✗ Branch 1 not taken.
|
3774 | fk->elements().size(), fk_columns_lambda); |
| 6378 | } | ||
| 6379 | |||
| 6380 | 1253 | bool prepare_fk_parent_key(handlerton *hton, const dd::Table *parent_table_def, | |
| 6381 | const dd::Table *old_parent_table_def, | ||
| 6382 | const dd::Table *old_child_table_def, | ||
| 6383 | bool is_self_referencing_fk, dd::Foreign_key *fk) { | ||
| 6384 | 1253 | const dd::Index *supporting_key = nullptr; | |
| 6385 | |||
| 6386 | /* | ||
| 6387 | For self referencing foreign keys, we should identify the supporting | ||
| 6388 | key to make sure it is not considered as a candidate parent key, | ||
| 6389 | unless the SE supports this. This function will be called for self | ||
| 6390 | referencing foreign keys only during upgrade from 5.7. | ||
| 6391 | */ | ||
| 6392 |
2/2✓ Branch 0 taken 22 times.
✓ Branch 1 taken 1231 times.
|
1253 | if (is_self_referencing_fk && |
| 6393 |
1/2✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
|
22 | (hton->foreign_keys_flags & |
| 6394 | HTON_FKS_NEED_DIFFERENT_PARENT_AND_SUPPORTING_KEYS)) { | ||
| 6395 | 22 | supporting_key = find_fk_supporting_key(hton, parent_table_def, fk); | |
| 6396 | } | ||
| 6397 | |||
| 6398 | const dd::Index *parent_key = | ||
| 6399 | 1253 | find_fk_parent_key(hton, supporting_key, parent_table_def, fk); | |
| 6400 | |||
| 6401 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1245 times.
|
1253 | if (parent_key == nullptr) { |
| 6402 | // No matching parent key in new table definition. | ||
| 6403 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 5 times.
|
8 | if (old_parent_table_def == nullptr) { |
| 6404 | /* | ||
| 6405 | No old version of parent table definition. This must be CREATE | ||
| 6406 | TABLE or RENAME TABLE (or possibly ALTER TABLE RENAME). | ||
| 6407 | */ | ||
| 6408 | 3 | my_error(ER_FK_NO_INDEX_PARENT, MYF(0), fk->name().c_str(), | |
| 6409 | 3 | fk->referenced_table_name().c_str()); | |
| 6410 | } else { | ||
| 6411 | /* | ||
| 6412 | This is ALTER TABLE which dropped parent key. | ||
| 6413 | |||
| 6414 | To report error we find original foreign key definition first. | ||
| 6415 | */ | ||
| 6416 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 | assert(old_child_table_def != nullptr); |
| 6417 | 16 | auto same_name = [fk](const dd::Foreign_key *el) { | |
| 6418 | 8 | return my_strcasecmp(system_charset_info, fk->name().c_str(), | |
| 6419 | 8 | el->name().c_str()) == 0; | |
| 6420 | 5 | }; | |
| 6421 | auto old_fk = | ||
| 6422 |
3/6✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
|
5 | std::find_if(old_child_table_def->foreign_keys().begin(), |
| 6423 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | old_child_table_def->foreign_keys().end(), same_name); |
| 6424 |
3/6✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5 times.
|
5 | assert(old_fk != old_child_table_def->foreign_keys().end()); |
| 6425 | |||
| 6426 | /* | ||
| 6427 | This function is normally called only for non-self referencing foreign | ||
| 6428 | keys. The only exception is during upgrade from 5.7, in which case | ||
| 6429 | old_parent_table_def == nullptr, which means that a different execution | ||
| 6430 | path is taken above. Hence, it is safe to submit nullptr as the | ||
| 6431 | supporting key in the call to find_fk_parent_key() below. | ||
| 6432 | */ | ||
| 6433 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 | assert(!is_self_referencing_fk); |
| 6434 | |||
| 6435 | /* | ||
| 6436 | And then try to find original parent key name. Just getting | ||
| 6437 | unique constraint name won't work for non-unique parent key. | ||
| 6438 | Ideally we should be using handlerton of old table version | ||
| 6439 | below, however, in practice, new table version's handlerton | ||
| 6440 | works just fine, since we do not allow changing of storage | ||
| 6441 | engines for tables with foreign keys. | ||
| 6442 | */ | ||
| 6443 | const dd::Index *old_pk = | ||
| 6444 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | find_fk_parent_key(hton, nullptr, old_parent_table_def, *old_fk); |
| 6445 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
10 | my_error(ER_DROP_INDEX_FK, MYF(0), |
| 6446 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | old_pk ? old_pk->name().c_str() : "<unknown key name>"); |
| 6447 | } | ||
| 6448 | 8 | return true; | |
| 6449 | } | ||
| 6450 | |||
| 6451 | /* | ||
| 6452 | If parent key is not PRIMARY/UNIQUE set UNIQUE_CONSTRAINT_NAME to | ||
| 6453 | NULL value. This is done by setting the name to "", which is | ||
| 6454 | interpreted as NULL when it is stored to the DD tables. | ||
| 6455 | */ | ||
| 6456 |
4/4✓ Branch 0 taken 127 times.
✓ Branch 1 taken 1118 times.
✓ Branch 2 taken 1146 times.
✓ Branch 3 taken 99 times.
|
1372 | if (parent_key->type() == dd::Index::IT_PRIMARY || |
| 6457 |
2/2✓ Branch 0 taken 28 times.
✓ Branch 1 taken 99 times.
|
127 | parent_key->type() == dd::Index::IT_UNIQUE) { |
| 6458 |
3/6✓ Branch 0 taken 1146 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1146 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1146 times.
✗ Branch 5 not taken.
|
1146 | fk->set_unique_constraint_name(parent_key->name().c_str()); |
| 6459 | } else { | ||
| 6460 |
2/4✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 99 times.
✗ Branch 3 not taken.
|
99 | fk->set_unique_constraint_name(""); |
| 6461 | } | ||
| 6462 | |||
| 6463 | 1245 | return false; | |
| 6464 | } | ||
| 6465 | |||
| 6466 | /** | ||
| 6467 | Helper which builds Ha_fk_column_type describing column type from | ||
| 6468 | its Create_field object. | ||
| 6469 | |||
| 6470 | @sa fill_dd_columns_from_create_fields(). | ||
| 6471 | */ | ||
| 6472 | |||
| 6473 | 350087 | static void fill_ha_fk_column_type(Ha_fk_column_type *fk_column_type, | |
| 6474 | const Create_field *field) { | ||
| 6475 | 350087 | fk_column_type->type = dd::get_new_field_type(field->sql_type); | |
| 6476 | 350087 | fk_column_type->char_length = field->max_display_width_in_bytes(); | |
| 6477 | 350087 | fk_column_type->field_charset = field->charset; | |
| 6478 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 350087 times.
|
350087 | fk_column_type->elements_count = field->interval ? field->interval->count : 0; |
| 6479 | 350087 | fk_column_type->numeric_scale = 0; | |
| 6480 | 350087 | dd::get_field_numeric_scale(field, &fk_column_type->numeric_scale); | |
| 6481 | 350087 | fk_column_type->is_unsigned = field->is_unsigned; | |
| 6482 | 350087 | } | |
| 6483 | |||
| 6484 | /** | ||
| 6485 | Helper which builds Ha_fk_column_type describing column type from | ||
| 6486 | its dd::Column object. | ||
| 6487 | */ | ||
| 6488 | |||
| 6489 | 328019 | static bool fill_ha_fk_column_type(Ha_fk_column_type *fk_column_type, | |
| 6490 | const dd::Column *column) { | ||
| 6491 | 328019 | fk_column_type->type = column->type(); | |
| 6492 | 328019 | fk_column_type->char_length = column->char_length(); | |
| 6493 | 328019 | fk_column_type->field_charset = dd_get_mysql_charset(column->collation_id()); | |
| 6494 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 328019 times.
|
328019 | if (fk_column_type->field_charset == nullptr) { |
| 6495 | ✗ | my_printf_error(ER_UNKNOWN_COLLATION, | |
| 6496 | "invalid collation id %llu for table %s, column %s", MYF(0), | ||
| 6497 | ✗ | column->collation_id(), column->table().name().c_str(), | |
| 6498 | ✗ | column->name().c_str()); | |
| 6499 | ✗ | return true; | |
| 6500 | } | ||
| 6501 | 328019 | fk_column_type->elements_count = column->elements_count(); | |
| 6502 | 328019 | fk_column_type->numeric_scale = column->numeric_scale(); | |
| 6503 | 328019 | fk_column_type->is_unsigned = column->is_unsigned(); | |
| 6504 | 328019 | return false; | |
| 6505 | } | ||
| 6506 | |||
| 6507 | /** | ||
| 6508 | Prepare FOREIGN_KEY struct with info about a foreign key. | ||
| 6509 | |||
| 6510 | @param thd Thread handle. | ||
| 6511 | @param create_info Create info from parser. | ||
| 6512 | @param alter_info Alter_info structure describing ALTER TABLE. | ||
| 6513 | @param db Database name. | ||
| 6514 | @param table_name Table name. | ||
| 6515 | @param is_partitioned Indicates whether table is partitioned. | ||
| 6516 | @param key_info_buffer Array of indexes. | ||
| 6517 | @param key_count Number of indexes. | ||
| 6518 | @param fk_info_all FOREIGN_KEY array with foreign keys which were | ||
| 6519 | already processed. | ||
| 6520 | @param fk_number Number of foreign keys which were already | ||
| 6521 | processed. | ||
| 6522 | @param se_supports_fks Indicates whether SE supports FKs. | ||
| 6523 | If not only basic FK validation is | ||
| 6524 | performed. | ||
| 6525 | @param find_parent_key Indicates whether we need to lookup name of unique | ||
| 6526 | constraint in parent table for the FK. | ||
| 6527 | @param[in,out] fk_key Parser info about new FK to | ||
| 6528 | prepare. | ||
| 6529 | @param[in,out] fk_max_generated_name_number Max value of number component | ||
| 6530 | among existing generated foreign | ||
| 6531 | key names. | ||
| 6532 | @param[out] fk_info Struct to populate. | ||
| 6533 | |||
| 6534 | @retval true if error (error reported), false otherwise. | ||
| 6535 | */ | ||
| 6536 | |||
| 6537 | 612874 | static bool prepare_foreign_key(THD *thd, HA_CREATE_INFO *create_info, | |
| 6538 | Alter_info *alter_info, const char *db, | ||
| 6539 | const char *table_name, bool is_partitioned, | ||
| 6540 | KEY *key_info_buffer, uint key_count, | ||
| 6541 | const FOREIGN_KEY *fk_info_all, uint fk_number, | ||
| 6542 | bool se_supports_fks, bool find_parent_key, | ||
| 6543 | Foreign_key_spec *fk_key, | ||
| 6544 | uint *fk_max_generated_name_number, | ||
| 6545 | FOREIGN_KEY *fk_info) { | ||
| 6546 |
1/2✓ Branch 0 taken 612874 times.
✗ Branch 1 not taken.
|
612874 | DBUG_TRACE; |
| 6547 | |||
| 6548 | // FKs are not supported for temporary tables. | ||
| 6549 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 612872 times.
|
612874 | if (create_info->options & HA_LEX_CREATE_TMP_TABLE) { |
| 6550 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | my_error(ER_CANNOT_ADD_FOREIGN, MYF(0), table_name); |
| 6551 | 2 | return true; | |
| 6552 | } | ||
| 6553 | |||
| 6554 | // FKs are not supported with CREATE TABLE ... START TRANSACTION. | ||
| 6555 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 612871 times.
|
612872 | if (create_info->m_transactional_ddl) { |
| 6556 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_FOREIGN_KEY_WITH_ATOMIC_CREATE_SELECT, MYF(0)); |
| 6557 | 1 | return true; | |
| 6558 | } | ||
| 6559 | |||
| 6560 | // Validate checks (among other things) that index prefixes are | ||
| 6561 | // not used and that generated columns are not used with | ||
| 6562 | // SET NULL and ON UPDATE CASCASE. Since this cannot change once | ||
| 6563 | // the FK has been made, it is enough to check it for new FKs. | ||
| 6564 |
3/4✓ Branch 0 taken 612871 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✓ Branch 3 taken 612852 times.
|
612871 | if (fk_key->validate(thd, table_name, alter_info->create_list)) return true; |
| 6565 | |||
| 6566 |
2/2✓ Branch 0 taken 34 times.
✓ Branch 1 taken 612818 times.
|
612852 | if (!se_supports_fks) return false; |
| 6567 | |||
| 6568 |
2/2✓ Branch 0 taken 681 times.
✓ Branch 1 taken 612137 times.
|
612818 | if (fk_key->has_explicit_name) { |
| 6569 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 681 times.
|
681 | assert(fk_key->name.str); |
| 6570 | 681 | fk_info->name = fk_key->name.str; | |
| 6571 | } else { | ||
| 6572 |
1/2✓ Branch 0 taken 612137 times.
✗ Branch 1 not taken.
|
612137 | fk_info->name = generate_fk_name(table_name, create_info->db_type, |
| 6573 | fk_max_generated_name_number); | ||
| 6574 | /* | ||
| 6575 | Update Foreign_key_spec::name member as some storage engines | ||
| 6576 | (e.g. NDB) rely on this information. To make this safe for | ||
| 6577 | prepared statement re-execution we have to employ | ||
| 6578 | Foreign_key_spec::has_explicit_name. Solving this issue in a | ||
| 6579 | better way requires change of approach which NDB uses to get | ||
| 6580 | info about added foreign keys. | ||
| 6581 | */ | ||
| 6582 |
1/2✓ Branch 0 taken 612137 times.
✗ Branch 1 not taken.
|
612137 | fk_key->name.str = thd->stmt_arena->mem_strdup(fk_info->name); |
| 6583 | 612137 | fk_key->name.length = strlen(fk_info->name); | |
| 6584 | |||
| 6585 | // Length of generated name should be checked as well. | ||
| 6586 |
3/4✓ Branch 0 taken 612137 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 612136 times.
|
612137 | if (check_string_char_length(to_lex_cstring(fk_info->name), "", |
| 6587 | NAME_CHAR_LEN, system_charset_info, true)) { | ||
| 6588 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_TOO_LONG_IDENT, MYF(0), fk_info->name); |
| 6589 | 1 | return true; | |
| 6590 | } | ||
| 6591 | } | ||
| 6592 | |||
| 6593 | /* | ||
| 6594 | Check that we are not creating several foreign keys with the same | ||
| 6595 | name over same table. This is mostly to avoid expensive phases of | ||
| 6596 | ALTER TABLE in such a case. Without this check the problem will be | ||
| 6597 | detected at the later stage when info about foreign keys is stored | ||
| 6598 | in data-dictionary. | ||
| 6599 | */ | ||
| 6600 |
2/2✓ Branch 0 taken 611719 times.
✓ Branch 1 taken 612812 times.
|
1224531 | for (uint fk_idx = 0; fk_idx < fk_number; fk_idx++) { |
| 6601 |
3/4✓ Branch 0 taken 611719 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 611714 times.
|
611719 | if (!my_strcasecmp(system_charset_info, fk_info_all[fk_idx].name, |
| 6602 | fk_info->name)) { | ||
| 6603 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | my_error(ER_FK_DUP_NAME, MYF(0), fk_info->name); |
| 6604 | 5 | return true; | |
| 6605 | } | ||
| 6606 | } | ||
| 6607 | |||
| 6608 | 612812 | fk_info->key_parts = fk_key->columns.size(); | |
| 6609 | |||
| 6610 | /* | ||
| 6611 | In --lower-case-table-names=2 mode we are to use lowercased versions of | ||
| 6612 | parent db and table names for acquiring MDL and lookup, but still need | ||
| 6613 | to store their original versions in the data-dictionary. | ||
| 6614 | */ | ||
| 6615 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 612812 times.
|
612812 | if (lower_case_table_names == 2) { |
| 6616 | ✗ | fk_info->ref_db = fk_key->orig_ref_db; | |
| 6617 | ✗ | fk_info->ref_table = fk_key->orig_ref_table; | |
| 6618 | } else { | ||
| 6619 | 612812 | fk_info->ref_db = fk_key->ref_db; | |
| 6620 | 612812 | fk_info->ref_table = fk_key->ref_table; | |
| 6621 | } | ||
| 6622 | |||
| 6623 | 612812 | fk_info->delete_opt = fk_key->delete_opt; | |
| 6624 | 612812 | fk_info->update_opt = fk_key->update_opt; | |
| 6625 | 612812 | fk_info->match_opt = fk_key->match_opt; | |
| 6626 | |||
| 6627 | 612812 | fk_info->key_part = reinterpret_cast<LEX_CSTRING *>( | |
| 6628 |
1/2✓ Branch 0 taken 612812 times.
✗ Branch 1 not taken.
|
612812 | thd->mem_calloc(sizeof(LEX_CSTRING) * fk_key->columns.size())); |
| 6629 | 612812 | fk_info->fk_key_part = reinterpret_cast<LEX_CSTRING *>( | |
| 6630 |
1/2✓ Branch 0 taken 612812 times.
✗ Branch 1 not taken.
|
612812 | thd->mem_calloc(sizeof(LEX_CSTRING) * fk_key->columns.size())); |
| 6631 | |||
| 6632 | 612812 | Prealloced_array<Create_field *, 1> referencing_fields(PSI_INSTRUMENT_ME); | |
| 6633 | |||
| 6634 |
2/2✓ Branch 0 taken 613270 times.
✓ Branch 1 taken 612802 times.
|
1226072 | for (size_t column_nr = 0; column_nr < fk_key->ref_columns.size(); |
| 6635 | column_nr++) { | ||
| 6636 |
1/2✓ Branch 0 taken 613270 times.
✗ Branch 1 not taken.
|
613270 | const Key_part_spec *col = fk_key->columns[column_nr]; |
| 6637 | |||
| 6638 | /* Check that referencing column exists and is not virtual. */ | ||
| 6639 |
1/2✓ Branch 0 taken 613270 times.
✗ Branch 1 not taken.
|
613270 | List_iterator<Create_field> find_it(alter_info->create_list); |
| 6640 | Create_field *find; | ||
| 6641 |
1/2✓ Branch 0 taken 5173160 times.
✗ Branch 1 not taken.
|
5173160 | while ((find = find_it++)) { |
| 6642 |
1/2✓ Branch 0 taken 5173160 times.
✗ Branch 1 not taken.
|
5173160 | if (my_strcasecmp(system_charset_info, col->get_field_name(), |
| 6643 |
2/2✓ Branch 0 taken 613270 times.
✓ Branch 1 taken 4559890 times.
|
5173160 | find->field_name) == 0) { |
| 6644 | 613270 | break; | |
| 6645 | } | ||
| 6646 | } | ||
| 6647 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 613270 times.
|
613270 | if (find == nullptr) { |
| 6648 | /* | ||
| 6649 | In practice this should not happen as wrong column name is caught | ||
| 6650 | during generated index processing and error with good enough message | ||
| 6651 | is reported. So we don't fuss about error message here. | ||
| 6652 | */ | ||
| 6653 | ✗ | my_error(ER_CANNOT_ADD_FOREIGN, MYF(0)); | |
| 6654 | 10 | return true; | |
| 6655 | } | ||
| 6656 | |||
| 6657 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 613267 times.
|
613270 | if (find->is_virtual_gcol()) { |
| 6658 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | my_error(ER_FK_CANNOT_USE_VIRTUAL_COLUMN, MYF(0), fk_info->name, |
| 6659 | col->get_field_name()); | ||
| 6660 | 3 | return true; | |
| 6661 | } | ||
| 6662 | |||
| 6663 | /* | ||
| 6664 | Foreign keys with SET NULL as one of referential actions do not | ||
| 6665 | make sense if any of referencing columns are non-nullable, so | ||
| 6666 | we prohibit them. | ||
| 6667 | */ | ||
| 6668 |
2/2✓ Branch 0 taken 613228 times.
✓ Branch 1 taken 39 times.
|
613267 | if ((fk_info->delete_opt == FK_OPTION_SET_NULL || |
| 6669 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 613196 times.
|
613228 | fk_info->update_opt == FK_OPTION_SET_NULL) && |
| 6670 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 70 times.
|
71 | find->flags & NOT_NULL_FLAG) { |
| 6671 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_FK_COLUMN_NOT_NULL, MYF(0), col->get_field_name(), |
| 6672 | fk_info->name); | ||
| 6673 | 1 | return true; | |
| 6674 | } | ||
| 6675 | |||
| 6676 | /* | ||
| 6677 | Check constraints evaluation is done before writing row to the storage | ||
| 6678 | engine but foreign key referential actions SET NULL, UPDATE CASCADE and | ||
| 6679 | SET DEFAULT are executed by the engine. Check constraints can not be | ||
| 6680 | evaluated for the these foreign key referential actions, so prohibit | ||
| 6681 | them. | ||
| 6682 | */ | ||
| 6683 |
2/2✓ Branch 0 taken 613228 times.
✓ Branch 1 taken 38 times.
|
613266 | if (fk_info->delete_opt == FK_OPTION_SET_NULL || |
| 6684 |
1/2✓ Branch 0 taken 613228 times.
✗ Branch 1 not taken.
|
613228 | fk_info->delete_opt == FK_OPTION_DEFAULT || |
| 6685 |
2/2✓ Branch 0 taken 613196 times.
✓ Branch 1 taken 32 times.
|
613228 | fk_info->update_opt == FK_OPTION_SET_NULL || |
| 6686 |
1/2✓ Branch 0 taken 613196 times.
✗ Branch 1 not taken.
|
613196 | fk_info->update_opt == FK_OPTION_DEFAULT || |
| 6687 |
2/2✓ Branch 0 taken 188 times.
✓ Branch 1 taken 613008 times.
|
613196 | fk_info->update_opt == FK_OPTION_CASCADE) { |
| 6688 |
3/4✓ Branch 0 taken 258 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 252 times.
|
267 | for (auto &cc_spec : alter_info->check_constraint_spec_list) { |
| 6689 |
3/4✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 9 times.
|
15 | if (cc_spec->expr_refers_column(find->field_name)) { |
| 6690 | 6 | my_error(ER_CHECK_CONSTRAINT_CLAUSE_USING_FK_REFER_ACTION_COLUMN, | |
| 6691 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | MYF(0), find->field_name, cc_spec->name.str, fk_info->name); |
| 6692 | 6 | return true; | |
| 6693 | } | ||
| 6694 | } | ||
| 6695 | } | ||
| 6696 | |||
| 6697 |
1/2✓ Branch 0 taken 613260 times.
✗ Branch 1 not taken.
|
613260 | referencing_fields.push_back(find); |
| 6698 | |||
| 6699 | /* | ||
| 6700 | Unlike for referenced columns, for referencing columns it doesn't matter | ||
| 6701 | which version of column name (i.e. coming from FOREIGN KEY clause or | ||
| 6702 | coming from table definition, they can differ in case) is stored in | ||
| 6703 | FOREIGN_KEY structure. Information about referencing columns is stored | ||
| 6704 | as their IDs in the data dictionary and as pointer to dd::Column object | ||
| 6705 | in in-memory representation. | ||
| 6706 | */ | ||
| 6707 | 613260 | fk_info->key_part[column_nr].str = col->get_field_name(); | |
| 6708 | 613260 | fk_info->key_part[column_nr].length = std::strlen(col->get_field_name()); | |
| 6709 | |||
| 6710 | /* | ||
| 6711 | Save version of referenced column name coming from FOREIGN KEY clause. | ||
| 6712 | Later we will replace it with version of name coming from parent table | ||
| 6713 | definition if possible (these versions can differ in case). | ||
| 6714 | */ | ||
| 6715 |
1/2✓ Branch 0 taken 613260 times.
✗ Branch 1 not taken.
|
613260 | const Key_part_spec *fk_col = fk_key->ref_columns[column_nr]; |
| 6716 | 613260 | fk_info->fk_key_part[column_nr].str = fk_col->get_field_name(); | |
| 6717 | 613260 | fk_info->fk_key_part[column_nr].length = | |
| 6718 | 613260 | std::strlen(fk_col->get_field_name()); | |
| 6719 | } | ||
| 6720 | |||
| 6721 |
1/2✓ Branch 0 taken 612802 times.
✗ Branch 1 not taken.
|
612802 | if (find_parent_key) { |
| 6722 | /* | ||
| 6723 | Check if we are trying to add foreign key to partitioned table | ||
| 6724 | and table's storage engine doesn't support foreign keys over | ||
| 6725 | partitioned tables. | ||
| 6726 | */ | ||
| 6727 |
4/4✓ Branch 0 taken 3 times.
✓ Branch 1 taken 612799 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 612799 times.
|
612805 | if (is_partitioned && |
| 6728 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | (!create_info->db_type->partition_flags || |
| 6729 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | create_info->db_type->partition_flags() & HA_CANNOT_PARTITION_FK)) { |
| 6730 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | my_error(ER_FOREIGN_KEY_ON_PARTITIONED, MYF(0)); |
| 6731 | 3 | return true; | |
| 6732 | } | ||
| 6733 | |||
| 6734 |
1/2✓ Branch 0 taken 612799 times.
✗ Branch 1 not taken.
|
612799 | const KEY *supporting_key = find_fk_supporting_key( |
| 6735 | create_info->db_type, alter_info, key_info_buffer, key_count, fk_info); | ||
| 6736 | |||
| 6737 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 612798 times.
|
612799 | if (supporting_key == nullptr) { |
| 6738 | /* | ||
| 6739 | Since we always add generated supporting key when adding new | ||
| 6740 | foreign key the failure to find key above is likely to mean | ||
| 6741 | that generated key was auto-converted to spatial key or it is | ||
| 6742 | some other corner case. | ||
| 6743 | */ | ||
| 6744 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_FK_NO_INDEX_CHILD, MYF(0), fk_info->name, table_name); |
| 6745 | 1 | return true; | |
| 6746 | } | ||
| 6747 | |||
| 6748 |
5/6✓ Branch 0 taken 612798 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 612783 times.
✓ Branch 3 taken 15 times.
✓ Branch 4 taken 12011 times.
✓ Branch 5 taken 600787 times.
|
1225581 | if (my_strcasecmp(table_alias_charset, fk_info->ref_db.str, db) == 0 && |
| 6749 |
3/4✓ Branch 0 taken 612783 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12011 times.
✓ Branch 3 taken 600772 times.
|
612783 | my_strcasecmp(table_alias_charset, fk_info->ref_table.str, |
| 6750 | table_name) == 0) { | ||
| 6751 | // FK which references the same table on which it is defined. | ||
| 6752 |
2/2✓ Branch 0 taken 12011 times.
✓ Branch 1 taken 12011 times.
|
24022 | for (uint i = 0; i < fk_info->key_parts; i++) { |
| 6753 |
1/2✓ Branch 0 taken 12011 times.
✗ Branch 1 not taken.
|
12011 | List_iterator_fast<Create_field> field_it(alter_info->create_list); |
| 6754 | const Create_field *field; | ||
| 6755 | |||
| 6756 | // Check that referenced column exists and is non-virtual. | ||
| 6757 |
1/2✓ Branch 0 taken 12012 times.
✗ Branch 1 not taken.
|
12012 | while ((field = field_it++)) { |
| 6758 |
1/2✓ Branch 0 taken 12012 times.
✗ Branch 1 not taken.
|
12012 | if (my_strcasecmp(system_charset_info, field->field_name, |
| 6759 |
2/2✓ Branch 0 taken 12011 times.
✓ Branch 1 taken 1 times.
|
12012 | fk_info->fk_key_part[i].str) == 0) |
| 6760 | 12011 | break; | |
| 6761 | } | ||
| 6762 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12011 times.
|
12011 | if (field == nullptr) { |
| 6763 | ✗ | my_error(ER_FK_NO_COLUMN_PARENT, MYF(0), fk_info->fk_key_part[i].str, | |
| 6764 | fk_info->name, fk_info->ref_table.str); | ||
| 6765 | ✗ | return true; | |
| 6766 | } | ||
| 6767 | |||
| 6768 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12011 times.
|
12011 | if (field->is_virtual_gcol()) { |
| 6769 | ✗ | my_error(ER_FK_CANNOT_USE_VIRTUAL_COLUMN, MYF(0), fk_info->name, | |
| 6770 | ✗ | fk_info->fk_key_part[i].str); | |
| 6771 | ✗ | return true; | |
| 6772 | } | ||
| 6773 | |||
| 6774 | // Check that types of referencing and referenced columns are | ||
| 6775 | // compatible. | ||
| 6776 |
1/2✓ Branch 0 taken 12011 times.
✗ Branch 1 not taken.
|
12011 | if (create_info->db_type->check_fk_column_compat) { |
| 6777 | Ha_fk_column_type child_column_type, parent_column_type; | ||
| 6778 | |||
| 6779 |
2/4✓ Branch 0 taken 12011 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12011 times.
✗ Branch 3 not taken.
|
12011 | fill_ha_fk_column_type(&child_column_type, referencing_fields[i]); |
| 6780 |
1/2✓ Branch 0 taken 12011 times.
✗ Branch 1 not taken.
|
12011 | fill_ha_fk_column_type(&parent_column_type, field); |
| 6781 | |||
| 6782 |
2/4✓ Branch 0 taken 12011 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 12011 times.
|
12011 | if (!create_info->db_type->check_fk_column_compat( |
| 6783 | &child_column_type, &parent_column_type, true)) { | ||
| 6784 | ✗ | my_error(ER_FK_INCOMPATIBLE_COLUMNS, MYF(0), | |
| 6785 | ✗ | fk_info->key_part[i].str, fk_info->fk_key_part[i].str, | |
| 6786 | fk_info->name); | ||
| 6787 | ✗ | return true; | |
| 6788 | } | ||
| 6789 | } | ||
| 6790 | |||
| 6791 | /* | ||
| 6792 | Be compatible with 5.7. Use version of referenced column name | ||
| 6793 | coming from parent table definition and not the one that was | ||
| 6794 | used in FOREIGN KEY clause. | ||
| 6795 | */ | ||
| 6796 | 12011 | fk_info->fk_key_part[i].str = field->field_name; | |
| 6797 | 12011 | fk_info->fk_key_part[i].length = std::strlen(field->field_name); | |
| 6798 | } | ||
| 6799 | |||
| 6800 |
3/4✓ Branch 0 taken 12011 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 12010 times.
|
12011 | if (prepare_self_ref_fk_parent_key(create_info->db_type, alter_info, |
| 6801 | key_info_buffer, key_count, | ||
| 6802 | supporting_key, nullptr, fk_info)) | ||
| 6803 | 1 | return true; | |
| 6804 | } else { | ||
| 6805 | /* | ||
| 6806 | FK which references other table than one on which it is defined. | ||
| 6807 | |||
| 6808 | Check that table exists and its storage engine as the first step. | ||
| 6809 | */ | ||
| 6810 | 600787 | const dd::Table *parent_table_def = nullptr; | |
| 6811 | |||
| 6812 |
4/8✓ Branch 0 taken 600787 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 600787 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 600787 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 600787 times.
|
600787 | if (thd->dd_client()->acquire(fk_info->ref_db.str, fk_info->ref_table.str, |
| 6813 | &parent_table_def)) | ||
| 6814 | 26 | return true; | |
| 6815 | |||
| 6816 | 600787 | handlerton *parent_hton = nullptr; | |
| 6817 |
3/4✓ Branch 0 taken 325245 times.
✓ Branch 1 taken 275542 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 600787 times.
|
926032 | if (parent_table_def != nullptr && |
| 6818 |
2/4✓ Branch 0 taken 325245 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 325245 times.
|
325245 | dd::table_storage_engine(thd, parent_table_def, &parent_hton)) |
| 6819 | ✗ | return true; | |
| 6820 | |||
| 6821 |
4/4✓ Branch 0 taken 325245 times.
✓ Branch 1 taken 275542 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 325240 times.
|
600787 | if (parent_table_def == nullptr || create_info->db_type != parent_hton) { |
| 6822 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 275541 times.
|
275547 | if (!(thd->variables.option_bits & OPTION_NO_FOREIGN_KEY_CHECKS)) { |
| 6823 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | my_error(ER_FK_CANNOT_OPEN_PARENT, MYF(0), fk_info->ref_table.str); |
| 6824 | 6 | return true; | |
| 6825 | } | ||
| 6826 | /* | ||
| 6827 | Missing parent table is legitimate case in FOREIGN_KEY_CHECKS=0 mode. | ||
| 6828 | |||
| 6829 | FOREIGN_KEY::unique_index_name should be already set to value which | ||
| 6830 | corresponds to NULL value in FOREIGN_KEYS.UNIQUE_CONSTRAINT_NAME | ||
| 6831 | column. | ||
| 6832 | |||
| 6833 | For compatibility reasons we treat difference in parent SE in the same | ||
| 6834 | way as missing parent table. | ||
| 6835 | */ | ||
| 6836 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 275541 times.
|
275541 | assert(fk_info->unique_index_name == nullptr); |
| 6837 | } else { | ||
| 6838 | /* | ||
| 6839 | Check that parent table is not partitioned or storage engine | ||
| 6840 | supports foreign keys over partitioned tables. | ||
| 6841 | */ | ||
| 6842 |
3/6✓ Branch 0 taken 325240 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 325240 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 325240 times.
|
325240 | if (parent_table_def->partition_type() != dd::Table::PT_NONE && |
| 6843 | ✗ | (!parent_hton->partition_flags || | |
| 6844 | ✗ | parent_hton->partition_flags() & HA_CANNOT_PARTITION_FK)) { | |
| 6845 | ✗ | my_error(ER_FOREIGN_KEY_ON_PARTITIONED, MYF(0)); | |
| 6846 | ✗ | return true; | |
| 6847 | } | ||
| 6848 | |||
| 6849 | /* Then check that referenced columns exist and are non-virtual. */ | ||
| 6850 |
2/2✓ Branch 0 taken 325696 times.
✓ Branch 1 taken 325232 times.
|
650928 | for (uint i = 0; i < fk_info->key_parts; i++) { |
| 6851 | 325696 | const char *ref_column_name = fk_info->fk_key_part[i].str; | |
| 6852 | |||
| 6853 | 326249 | auto same_column_name = [ref_column_name](const dd::Column *c) { | |
| 6854 | 326249 | return my_strcasecmp(system_charset_info, c->name().c_str(), | |
| 6855 | 326249 | ref_column_name) == 0; | |
| 6856 | 325696 | }; | |
| 6857 | |||
| 6858 | auto ref_column = | ||
| 6859 |
3/6✓ Branch 0 taken 325696 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 325696 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 325696 times.
✗ Branch 5 not taken.
|
325696 | std::find_if(parent_table_def->columns().begin(), |
| 6860 |
2/4✓ Branch 0 taken 325696 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 325696 times.
✗ Branch 3 not taken.
|
325696 | parent_table_def->columns().end(), same_column_name); |
| 6861 | |||
| 6862 |
3/6✓ Branch 0 taken 325696 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 325696 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 325696 times.
|
325696 | if (ref_column == parent_table_def->columns().end()) { |
| 6863 | ✗ | my_error(ER_FK_NO_COLUMN_PARENT, MYF(0), ref_column_name, | |
| 6864 | fk_info->name, fk_info->ref_table.str); | ||
| 6865 | 8 | return true; | |
| 6866 | } | ||
| 6867 | |||
| 6868 |
4/6✓ Branch 0 taken 325696 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 325696 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 325694 times.
|
325696 | if ((*ref_column)->is_virtual()) { |
| 6869 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | my_error(ER_FK_CANNOT_USE_VIRTUAL_COLUMN, MYF(0), fk_info->name, |
| 6870 | ref_column_name); | ||
| 6871 | 2 | return true; | |
| 6872 | } | ||
| 6873 | |||
| 6874 | // Check that types of referencing and referenced columns are | ||
| 6875 | // compatible. | ||
| 6876 |
1/2✓ Branch 0 taken 325694 times.
✗ Branch 1 not taken.
|
325694 | if (create_info->db_type->check_fk_column_compat) { |
| 6877 | Ha_fk_column_type child_column_type, parent_column_type; | ||
| 6878 | |||
| 6879 |
2/4✓ Branch 0 taken 325694 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 325694 times.
✗ Branch 3 not taken.
|
325694 | fill_ha_fk_column_type(&child_column_type, referencing_fields[i]); |
| 6880 |
3/6✓ Branch 0 taken 325694 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 325694 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 325694 times.
|
325694 | if (fill_ha_fk_column_type(&parent_column_type, *ref_column)) |
| 6881 | 6 | return true; | |
| 6882 | |||
| 6883 |
3/4✓ Branch 0 taken 325694 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 325688 times.
|
325694 | if (!create_info->db_type->check_fk_column_compat( |
| 6884 | &child_column_type, &parent_column_type, true)) { | ||
| 6885 | 6 | my_error(ER_FK_INCOMPATIBLE_COLUMNS, MYF(0), | |
| 6886 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | fk_info->key_part[i].str, ref_column_name, |
| 6887 | fk_info->name); | ||
| 6888 | 6 | return true; | |
| 6889 | } | ||
| 6890 | } | ||
| 6891 | |||
| 6892 | /* | ||
| 6893 | Be compatible with 5.7. Use version of referenced column name | ||
| 6894 | coming from parent table definition and not the one that was | ||
| 6895 | used in FOREIGN KEY clause. | ||
| 6896 | */ | ||
| 6897 |
2/4✓ Branch 0 taken 325688 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 325688 times.
✗ Branch 3 not taken.
|
325688 | fk_info->fk_key_part[i].str = (*ref_column)->name().c_str(); |
| 6898 |
2/4✓ Branch 0 taken 325688 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 325688 times.
✗ Branch 3 not taken.
|
325688 | fk_info->fk_key_part[i].length = (*ref_column)->name().length(); |
| 6899 | } | ||
| 6900 | |||
| 6901 |
3/4✓ Branch 0 taken 325232 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 325220 times.
|
325232 | if (prepare_fk_parent_key(create_info->db_type, parent_table_def, |
| 6902 | fk_info)) | ||
| 6903 | 12 | return true; | |
| 6904 | } | ||
| 6905 | } | ||
| 6906 | } else { | ||
| 6907 | ✗ | assert(fk_info->unique_index_name == nullptr); | |
| 6908 | } | ||
| 6909 | |||
| 6910 | 612771 | return false; | |
| 6911 | 612874 | } | |
| 6912 | |||
| 6913 | /** | ||
| 6914 | Check that pre-existing self-referencing foreign key or an orphan | ||
| 6915 | non-self-referencing foreign key become non-orphan/adopted self-referencing | ||
| 6916 | foreign key as a result of table rename operation will be valid after ALTER | ||
| 6917 | TABLE, i.e. that table has parent index and types of child and parent | ||
| 6918 | columns are compatible. Also update DD.UNIQUE_CONSTRAINT_NAME accordingly. | ||
| 6919 | |||
| 6920 | @param thd Thread context.. | ||
| 6921 | @param create_info HA_CREATE_INFO describing table. | ||
| 6922 | @param alter_info Alter_info structure describing | ||
| 6923 | table. | ||
| 6924 | @param key_info Array of indexes. | ||
| 6925 | @param key_count Number of indexes. | ||
| 6926 | @param supporting_key Supporting key for the foreign key. | ||
| 6927 | @param existing_fks_table dd::Table object for table version | ||
| 6928 | from which pre-existing foreign keys | ||
| 6929 | come from. Needed for error | ||
| 6930 | reporting. | ||
| 6931 | @param referencing_fields List of foreign key referencing fields. | ||
| 6932 | @param[in,out] fk FOREIGN_KEY object describing | ||
| 6933 | pre-existing foreign key. | ||
| 6934 | |||
| 6935 | @retval true if error (error reported), false otherwise. | ||
| 6936 | */ | ||
| 6937 | 1 | static bool prepare_preexisting_self_ref_foreign_key( | |
| 6938 | THD *thd, HA_CREATE_INFO *create_info, Alter_info *alter_info, | ||
| 6939 | KEY *key_info, uint key_count, const KEY *supporting_key, | ||
| 6940 | const dd::Table *existing_fks_table, FOREIGN_KEY *fk, | ||
| 6941 | const Prealloced_array<Create_field *, 1> &referencing_fields) { | ||
| 6942 | Create_field *sql_field; | ||
| 6943 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | List_iterator<Create_field> it(alter_info->create_list); |
| 6944 | |||
| 6945 | // Check that types of child and parent columns are still compatible. | ||
| 6946 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (create_info->db_type->check_fk_column_compat) { |
| 6947 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | for (size_t j = 0; j < fk->key_parts; j++) { |
| 6948 | 1 | it.rewind(); | |
| 6949 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | while ((sql_field = it++)) { |
| 6950 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (my_strcasecmp(system_charset_info, fk->fk_key_part[j].str, |
| 6951 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | sql_field->field_name) == 0) |
| 6952 | 1 | break; | |
| 6953 | } | ||
| 6954 | // We already have checked that referenced column exists. | ||
| 6955 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | assert(sql_field != nullptr); |
| 6956 | |||
| 6957 | Ha_fk_column_type child_column_type, parent_column_type; | ||
| 6958 | |||
| 6959 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | fill_ha_fk_column_type(&child_column_type, referencing_fields[j]); |
| 6960 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | fill_ha_fk_column_type(&parent_column_type, sql_field); |
| 6961 | |||
| 6962 | /* | ||
| 6963 | Allow charset discrepancies between child and parent columns | ||
| 6964 | in FOREIGN_KEY_CHECKS=0 mode. This provides a way to change | ||
| 6965 | charset of column which participates in a foreign key without | ||
| 6966 | dropping the latter. | ||
| 6967 | We allow such discrepancies even for foreign keys that has same | ||
| 6968 | table as child and parent in order to be consistent with general | ||
| 6969 | case, in which there is no way to change charset of both child | ||
| 6970 | and parent columns simultaneously. | ||
| 6971 | |||
| 6972 | We do not allow creation of same discrepancies when adding | ||
| 6973 | new foreign key using CREATE/ALTER TABLE or adding new parent | ||
| 6974 | for existing orphan foreign key using CREATE/RENAME TABLE. | ||
| 6975 | */ | ||
| 6976 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (!create_info->db_type->check_fk_column_compat( |
| 6977 | &child_column_type, &parent_column_type, | ||
| 6978 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | !(thd->variables.option_bits & OPTION_NO_FOREIGN_KEY_CHECKS))) { |
| 6979 | ✗ | my_error(ER_FK_INCOMPATIBLE_COLUMNS, MYF(0), fk->key_part[j].str, | |
| 6980 | ✗ | fk->fk_key_part[j].str, fk->name); | |
| 6981 | ✗ | return true; | |
| 6982 | } | ||
| 6983 | } | ||
| 6984 | } | ||
| 6985 | |||
| 6986 | /* | ||
| 6987 | Check that foreign key still has matching parent key and adjust | ||
| 6988 | DD.UNIQUE_CONSTRAINT_NAME accordingly. | ||
| 6989 | */ | ||
| 6990 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | if (prepare_self_ref_fk_parent_key(create_info->db_type, alter_info, key_info, |
| 6991 | key_count, supporting_key, | ||
| 6992 | existing_fks_table, fk)) | ||
| 6993 | ✗ | return true; | |
| 6994 | |||
| 6995 | 1 | return false; | |
| 6996 | } | ||
| 6997 | |||
| 6998 | /** | ||
| 6999 | Check that pre-existing foreign key will be still valid after ALTER TABLE, | ||
| 7000 | i.e. that table still has supporting index and types of child and parent | ||
| 7001 | columns are still compatible. Also if necessary check that there is parent | ||
| 7002 | index and update DD.UNIQUE_CONSTRAINT_NAME accordingly. | ||
| 7003 | |||
| 7004 | @param thd Thread context.. | ||
| 7005 | @param create_info HA_CREATE_INFO describing table. | ||
| 7006 | @param alter_info Alter_info structure describing | ||
| 7007 | ALTER TABLE. | ||
| 7008 | @param schema_name Table schema name. | ||
| 7009 | @param table_name Table name. | ||
| 7010 | @param key_info Array of indexes. | ||
| 7011 | @param key_count Number of indexes. | ||
| 7012 | @param existing_fks_table dd::Table object for table version | ||
| 7013 | from which pre-existing foreign keys | ||
| 7014 | come from. Needed for error | ||
| 7015 | reporting. | ||
| 7016 | @param[in,out] fk FOREIGN_KEY object describing | ||
| 7017 | pre-existing foreign key. | ||
| 7018 | |||
| 7019 | @retval true if error (error reported), false otherwise. | ||
| 7020 | */ | ||
| 7021 | 264 | static bool prepare_preexisting_foreign_key( | |
| 7022 | THD *thd, HA_CREATE_INFO *create_info, Alter_info *alter_info, | ||
| 7023 | const char *schema_name, const char *table_name, KEY *key_info, | ||
| 7024 | uint key_count, const dd::Table *existing_fks_table, FOREIGN_KEY *fk) { | ||
| 7025 | Create_field *sql_field; | ||
| 7026 |
1/2✓ Branch 0 taken 264 times.
✗ Branch 1 not taken.
|
264 | List_iterator<Create_field> it(alter_info->create_list); |
| 7027 | 264 | Prealloced_array<Create_field *, 1> referencing_fields(PSI_INSTRUMENT_ME); | |
| 7028 | |||
| 7029 |
2/2✓ Branch 0 taken 297 times.
✓ Branch 1 taken 255 times.
|
552 | for (size_t j = 0; j < fk->key_parts; j++) { |
| 7030 | 297 | it.rewind(); | |
| 7031 |
1/2✓ Branch 0 taken 700 times.
✗ Branch 1 not taken.
|
700 | while ((sql_field = it++)) { |
| 7032 |
1/2✓ Branch 0 taken 700 times.
✗ Branch 1 not taken.
|
700 | if (my_strcasecmp(system_charset_info, fk->key_part[j].str, |
| 7033 |
2/2✓ Branch 0 taken 297 times.
✓ Branch 1 taken 403 times.
|
700 | sql_field->field_name) == 0) |
| 7034 | 297 | break; | |
| 7035 | } | ||
| 7036 | // We already have checked that referencing column exists. | ||
| 7037 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 297 times.
|
297 | assert(sql_field != nullptr); |
| 7038 | // Save Create_field to be used in type compatibility check later. | ||
| 7039 |
1/2✓ Branch 0 taken 297 times.
✗ Branch 1 not taken.
|
297 | referencing_fields.push_back(sql_field); |
| 7040 | |||
| 7041 | /* | ||
| 7042 | Check if this foreign key has SET NULL as one of referential actions | ||
| 7043 | and one of its referencing columns became non-nullable. | ||
| 7044 | |||
| 7045 | We do this check here rather than in transfer_preexisting_foreign_keys() | ||
| 7046 | in order to avoid complicated handling of case when column becomes | ||
| 7047 | non-nullable implicitly because it is part of PRIMARY KEY added. | ||
| 7048 | */ | ||
| 7049 |
2/2✓ Branch 0 taken 268 times.
✓ Branch 1 taken 29 times.
|
297 | if ((fk->delete_opt == FK_OPTION_SET_NULL || |
| 7050 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 263 times.
|
268 | fk->update_opt == FK_OPTION_SET_NULL) && |
| 7051 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 28 times.
|
34 | (sql_field->flags & NOT_NULL_FLAG)) { |
| 7052 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | my_error(ER_FK_COLUMN_NOT_NULL, MYF(0), fk->key_part[j].str, fk->name); |
| 7053 | 6 | return true; | |
| 7054 | } | ||
| 7055 | |||
| 7056 | /* | ||
| 7057 | Check constraints evaluation is done before writing row to the storage | ||
| 7058 | engine but foreign key referential actions SET NULL, UPDATE CASCADE and | ||
| 7059 | SET DEFAULT are executed by the engine. Check constraints can not be | ||
| 7060 | evaluated for the these foreign key referential actions, so we prohibit | ||
| 7061 | them. | ||
| 7062 | */ | ||
| 7063 |
2/2✓ Branch 0 taken 267 times.
✓ Branch 1 taken 24 times.
|
291 | if (fk->delete_opt == FK_OPTION_SET_NULL || |
| 7064 |
1/2✓ Branch 0 taken 267 times.
✗ Branch 1 not taken.
|
267 | fk->delete_opt == FK_OPTION_DEFAULT || |
| 7065 |
2/2✓ Branch 0 taken 263 times.
✓ Branch 1 taken 4 times.
|
267 | fk->update_opt == FK_OPTION_SET_NULL || |
| 7066 |
1/2✓ Branch 0 taken 263 times.
✗ Branch 1 not taken.
|
263 | fk->update_opt == FK_OPTION_DEFAULT || |
| 7067 |
2/2✓ Branch 0 taken 86 times.
✓ Branch 1 taken 177 times.
|
263 | fk->update_opt == FK_OPTION_CASCADE) { |
| 7068 |
3/4✓ Branch 0 taken 114 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 111 times.
|
117 | for (auto &cc_spec : alter_info->check_constraint_spec_list) { |
| 7069 |
3/4✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 3 times.
|
6 | if (cc_spec->expr_refers_column(sql_field->field_name)) { |
| 7070 | 3 | my_error(ER_CHECK_CONSTRAINT_CLAUSE_USING_FK_REFER_ACTION_COLUMN, | |
| 7071 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | MYF(0), sql_field->field_name, cc_spec->name.str, fk->name); |
| 7072 | 3 | return true; | |
| 7073 | } | ||
| 7074 | } | ||
| 7075 | } | ||
| 7076 | } | ||
| 7077 | |||
| 7078 | // Check that we still have supporting index on child table. | ||
| 7079 |
1/2✓ Branch 0 taken 255 times.
✗ Branch 1 not taken.
|
255 | const KEY *supporting_key = find_fk_supporting_key( |
| 7080 | create_info->db_type, alter_info, key_info, key_count, fk); | ||
| 7081 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 241 times.
|
255 | if (supporting_key == nullptr) { |
| 7082 | /* | ||
| 7083 | If there is no supporting index, it must have been dropped by | ||
| 7084 | this ALTER TABLE. Find old foreign key definition and supporting | ||
| 7085 | index which matched it in old table definition in order to report | ||
| 7086 | nice error. | ||
| 7087 | */ | ||
| 7088 | 34 | auto same_name = [fk](const dd::Foreign_key *el) { | |
| 7089 | 17 | return my_strcasecmp(system_charset_info, fk->name, el->name().c_str()) == | |
| 7090 | 17 | 0; | |
| 7091 | 14 | }; | |
| 7092 | auto old_fk = | ||
| 7093 |
3/6✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
|
14 | std::find_if(existing_fks_table->foreign_keys().begin(), |
| 7094 |
2/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
14 | existing_fks_table->foreign_keys().end(), same_name); |
| 7095 |
3/6✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 14 times.
|
14 | assert(old_fk != existing_fks_table->foreign_keys().end()); |
| 7096 | |||
| 7097 | 28 | const dd::Index *old_key = find_fk_supporting_key( | |
| 7098 |
2/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
14 | create_info->db_type, existing_fks_table, *old_fk); |
| 7099 |
2/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
28 | my_error(ER_DROP_INDEX_FK, MYF(0), |
| 7100 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | old_key ? old_key->name().c_str() : "<unknown key name>"); |
| 7101 | 14 | return true; | |
| 7102 | } | ||
| 7103 | |||
| 7104 |
5/6✓ Branch 0 taken 241 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 237 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 240 times.
|
478 | if (my_strcasecmp(table_alias_charset, fk->ref_db.str, schema_name) == 0 && |
| 7105 |
3/4✓ Branch 0 taken 237 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 236 times.
|
237 | my_strcasecmp(table_alias_charset, fk->ref_table.str, table_name) == 0) { |
| 7106 | // Pre-existing foreign key which has same table as parent and child. | ||
| 7107 | |||
| 7108 | // TODO: Run this check only in cases when column type is really changed in | ||
| 7109 | // order to avoid unnecessary work. | ||
| 7110 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | if (prepare_preexisting_self_ref_foreign_key( |
| 7111 | thd, create_info, alter_info, key_info, key_count, supporting_key, | ||
| 7112 | existing_fks_table, fk, referencing_fields)) | ||
| 7113 | ✗ | return true; | |
| 7114 | 481 | } else if (alter_info->new_table_name.str != nullptr && | |
| 7115 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | my_strcasecmp(table_alias_charset, fk->ref_db.str, |
| 7116 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 239 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 240 times.
|
241 | alter_info->new_db_name.str) == 0 && |
| 7117 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | my_strcasecmp(table_alias_charset, fk->ref_table.str, |
| 7118 | alter_info->new_table_name.str) == 0) { | ||
| 7119 | /* | ||
| 7120 | Pre-existing orphan non-self-referencing foreign key become | ||
| 7121 | non-orphan/adopted self-referencing foreign key as a result of table | ||
| 7122 | rename operation. | ||
| 7123 | */ | ||
| 7124 | ✗ | if (prepare_preexisting_self_ref_foreign_key( | |
| 7125 | thd, create_info, alter_info, key_info, key_count, supporting_key, | ||
| 7126 | nullptr, fk, referencing_fields)) | ||
| 7127 | ✗ | return true; | |
| 7128 | } else { | ||
| 7129 | /* | ||
| 7130 | Pre-existing foreign key with different tables as child and parent. | ||
| 7131 | |||
| 7132 | There is no need to update DD.UNIQUE_CONSTRAINT_NAME. | ||
| 7133 | |||
| 7134 | Parent table definition is needed to check column types compatibility. | ||
| 7135 | |||
| 7136 | Skip check if parent table doesn't exist or uses wrong engine. | ||
| 7137 | */ | ||
| 7138 |
1/2✓ Branch 0 taken 240 times.
✗ Branch 1 not taken.
|
240 | if (create_info->db_type->check_fk_column_compat) { |
| 7139 | 240 | const dd::Table *parent_table_def = nullptr; | |
| 7140 |
4/8✓ Branch 0 taken 240 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 240 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 240 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 240 times.
|
240 | if (thd->dd_client()->acquire(fk->ref_db.str, fk->ref_table.str, |
| 7141 | &parent_table_def)) | ||
| 7142 | ✗ | return true; | |
| 7143 | |||
| 7144 | 240 | handlerton *parent_hton = nullptr; | |
| 7145 |
3/4✓ Branch 0 taken 236 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 240 times.
|
476 | if (parent_table_def != nullptr && |
| 7146 |
2/4✓ Branch 0 taken 236 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 236 times.
|
236 | dd::table_storage_engine(thd, parent_table_def, &parent_hton)) |
| 7147 | ✗ | return true; | |
| 7148 | |||
| 7149 |
3/4✓ Branch 0 taken 236 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 236 times.
✗ Branch 3 not taken.
|
240 | if (parent_table_def != nullptr && create_info->db_type == parent_hton) { |
| 7150 |
2/2✓ Branch 0 taken 269 times.
✓ Branch 1 taken 236 times.
|
505 | for (size_t j = 0; j < fk->key_parts; j++) { |
| 7151 | 269 | const char *ref_column_name = fk->fk_key_part[j].str; | |
| 7152 | |||
| 7153 | 338 | auto same_column_name = [ref_column_name](const dd::Column *c) { | |
| 7154 | 338 | return my_strcasecmp(system_charset_info, c->name().c_str(), | |
| 7155 | 338 | ref_column_name) == 0; | |
| 7156 | 269 | }; | |
| 7157 | |||
| 7158 | auto ref_column = | ||
| 7159 |
3/6✓ Branch 0 taken 269 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 269 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 269 times.
✗ Branch 5 not taken.
|
269 | std::find_if(parent_table_def->columns().begin(), |
| 7160 |
2/4✓ Branch 0 taken 269 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 269 times.
✗ Branch 3 not taken.
|
269 | parent_table_def->columns().end(), same_column_name); |
| 7161 |
3/6✓ Branch 0 taken 269 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 269 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 269 times.
|
269 | assert(ref_column != parent_table_def->columns().end()); |
| 7162 | |||
| 7163 | Ha_fk_column_type child_column_type, parent_column_type; | ||
| 7164 | |||
| 7165 |
2/4✓ Branch 0 taken 269 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 269 times.
✗ Branch 3 not taken.
|
269 | fill_ha_fk_column_type(&child_column_type, referencing_fields[j]); |
| 7166 |
3/6✓ Branch 0 taken 269 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 269 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 269 times.
|
269 | if (fill_ha_fk_column_type(&parent_column_type, *ref_column)) |
| 7167 | ✗ | return true; | |
| 7168 | |||
| 7169 | /* | ||
| 7170 | See comment in prepare_preexisting_self_ref_foreign_key() about | ||
| 7171 | allowing charset discrepancies between child and parent columns in | ||
| 7172 | FOREIGN_KEY_CHECKS=0 mode. | ||
| 7173 | */ | ||
| 7174 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 269 times.
|
269 | if (!create_info->db_type->check_fk_column_compat( |
| 7175 | &child_column_type, &parent_column_type, | ||
| 7176 |
1/2✓ Branch 0 taken 269 times.
✗ Branch 1 not taken.
|
269 | !(thd->variables.option_bits & |
| 7177 | OPTION_NO_FOREIGN_KEY_CHECKS))) { | ||
| 7178 | ✗ | my_error(ER_FK_INCOMPATIBLE_COLUMNS, MYF(0), fk->key_part[j].str, | |
| 7179 | ref_column_name, fk->name); | ||
| 7180 | ✗ | return true; | |
| 7181 | } | ||
| 7182 | } | ||
| 7183 | } | ||
| 7184 | } | ||
| 7185 | } | ||
| 7186 | 241 | return false; | |
| 7187 | 264 | } | |
| 7188 | |||
| 7189 | 1466549 | static bool prepare_key( | |
| 7190 | THD *thd, const char *error_schema_name, const char *error_table_name, | ||
| 7191 | HA_CREATE_INFO *create_info, List<Create_field> *create_list, | ||
| 7192 | const Key_spec *key, KEY **key_info_buffer, KEY *key_info, | ||
| 7193 | KEY_PART_INFO **key_part_info, Mem_root_array<const KEY *> &keys_to_check, | ||
| 7194 | uint key_number, const handler *file, int *auto_increment) { | ||
| 7195 |
1/2✓ Branch 0 taken 1466550 times.
✗ Branch 1 not taken.
|
1466549 | DBUG_TRACE; |
| 7196 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1466550 times.
|
1466550 | assert(create_list); |
| 7197 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1466550 times.
|
1466550 | assert(key_info->flags == 0); // No flags should be set yet |
| 7198 | |||
| 7199 | /* | ||
| 7200 | General checks. | ||
| 7201 | */ | ||
| 7202 | |||
| 7203 |
5/6✓ Branch 0 taken 1466550 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1466548 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1466549 times.
|
1466552 | if (key->columns.size() > file->max_key_parts() && |
| 7204 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | key->type != KEYTYPE_SPATIAL) { |
| 7205 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | my_error(ER_TOO_MANY_KEY_PARTS, MYF(0), file->max_key_parts()); |
| 7206 | 1 | return true; | |
| 7207 | } | ||
| 7208 | |||
| 7209 |
3/4✓ Branch 0 taken 1466548 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1466547 times.
|
1466549 | if (check_string_char_length(key->name, "", NAME_CHAR_LEN, |
| 7210 | system_charset_info, true)) { | ||
| 7211 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_TOO_LONG_IDENT, MYF(0), key->name.str); |
| 7212 | 1 | return true; | |
| 7213 | } | ||
| 7214 | |||
| 7215 |
6/6✓ Branch 0 taken 139362 times.
✓ Branch 1 taken 1327185 times.
✓ Branch 2 taken 85724 times.
✓ Branch 3 taken 53638 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 1466543 times.
|
1552271 | if (key->name.str && (key->type != KEYTYPE_PRIMARY) && |
| 7216 |
3/4✓ Branch 0 taken 85724 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 85720 times.
|
85724 | !my_strcasecmp(system_charset_info, key->name.str, primary_key_name)) { |
| 7217 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key->name.str); |
| 7218 | 4 | return true; | |
| 7219 | } | ||
| 7220 | |||
| 7221 | /* Create the key name based on the first column (if not given) */ | ||
| 7222 |
2/2✓ Branch 0 taken 500995 times.
✓ Branch 1 taken 965548 times.
|
1466543 | if (key->type == KEYTYPE_PRIMARY) |
| 7223 | 500995 | key_info->name = primary_key_name; | |
| 7224 |
2/2✓ Branch 0 taken 85720 times.
✓ Branch 1 taken 879828 times.
|
965548 | else if (key->name.str) |
| 7225 | 85720 | key_info->name = key->name.str; | |
| 7226 | else { | ||
| 7227 |
1/2✓ Branch 0 taken 879828 times.
✗ Branch 1 not taken.
|
879828 | const Key_part_spec *first_col = key->columns[0]; |
| 7228 |
1/2✓ Branch 0 taken 879828 times.
✗ Branch 1 not taken.
|
879828 | List_iterator<Create_field> it(*create_list); |
| 7229 | Create_field *sql_field; | ||
| 7230 |
4/4✓ Branch 0 taken 6534705 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 5654895 times.
✓ Branch 3 taken 879828 times.
|
7414551 | while ((sql_field = it++) && |
| 7231 |
3/4✓ Branch 0 taken 6534705 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5654895 times.
✓ Branch 3 taken 879810 times.
|
6534705 | my_strcasecmp(system_charset_info, first_col->get_field_name(), |
| 7232 | sql_field->field_name)) | ||
| 7233 | ; | ||
| 7234 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 879810 times.
|
879828 | if (!sql_field) { |
| 7235 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), |
| 7236 | first_col->get_field_name()); | ||
| 7237 | 18 | return true; | |
| 7238 | } | ||
| 7239 | 1759620 | key_info->name = | |
| 7240 |
1/2✓ Branch 0 taken 879810 times.
✗ Branch 1 not taken.
|
879810 | make_unique_key_name(sql_field->field_name, *key_info_buffer, key_info); |
| 7241 | } | ||
| 7242 |
4/4✓ Branch 0 taken 965530 times.
✓ Branch 1 taken 500995 times.
✓ Branch 2 taken 989 times.
✓ Branch 3 taken 1465536 times.
|
2432055 | if (key->type != KEYTYPE_PRIMARY && |
| 7243 |
3/4✓ Branch 0 taken 965530 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 989 times.
✓ Branch 3 taken 964541 times.
|
965530 | check_if_keyname_exists(key_info->name, *key_info_buffer, key_info)) { |
| 7244 |
1/2✓ Branch 0 taken 989 times.
✗ Branch 1 not taken.
|
989 | my_error(ER_DUP_KEYNAME, MYF(0), key_info->name); |
| 7245 | 989 | return true; | |
| 7246 | } | ||
| 7247 | |||
| 7248 |
6/8✓ Branch 0 taken 1465536 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1465537 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 1465535 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 1465535 times.
|
1465536 | if (!key_info->name || check_column_name(key_info->name)) { |
| 7249 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key_info->name); |
| 7250 | 2 | return true; | |
| 7251 | } | ||
| 7252 | |||
| 7253 | 1465535 | key_info->comment.length = key->key_create_info.comment.length; | |
| 7254 | 1465535 | key_info->comment.str = key->key_create_info.comment.str; | |
| 7255 | |||
| 7256 | // Validate index comment string | ||
| 7257 | 1465535 | std::string invalid_sub_str; | |
| 7258 |
3/4✓ Branch 0 taken 1465534 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1465533 times.
|
1465535 | if (is_invalid_string({key_info->comment.str, key_info->comment.length}, |
| 7259 | system_charset_info, invalid_sub_str)) { | ||
| 7260 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
2 | my_error(ER_COMMENT_CONTAINS_INVALID_STRING, MYF(0), "index", |
| 7261 |
3/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
2 | (std::string(error_schema_name) + "." + |
| 7262 |
4/8✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
|
4 | std::string(error_table_name) + "." + std::string(key->name.str)) |
| 7263 | .c_str(), | ||
| 7264 | system_charset_info->csname, invalid_sub_str.c_str()); | ||
| 7265 | 1 | return true; | |
| 7266 | } | ||
| 7267 | |||
| 7268 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1465528 times.
|
1465534 | if (validate_comment_length(thd, key_info->comment.str, |
| 7269 |
1/2✓ Branch 0 taken 1465534 times.
✗ Branch 1 not taken.
|
1465533 | &key_info->comment.length, INDEX_COMMENT_MAXLEN, |
| 7270 | ER_TOO_LONG_INDEX_COMMENT, key_info->name)) | ||
| 7271 | 6 | return true; | |
| 7272 |
2/2✓ Branch 0 taken 1622 times.
✓ Branch 1 taken 1463906 times.
|
1465528 | if (key_info->comment.length > 0) key_info->flags |= HA_USES_COMMENT; |
| 7273 | |||
| 7274 | 1465528 | key_info->engine_attribute = key->key_create_info.m_engine_attribute; | |
| 7275 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 1465513 times.
|
1465528 | if (key_info->engine_attribute.length > 0) |
| 7276 | 15 | key_info->flags |= HA_INDEX_USES_ENGINE_ATTRIBUTE; | |
| 7277 | 1465528 | key_info->secondary_engine_attribute = | |
| 7278 | key->key_create_info.m_secondary_engine_attribute; | ||
| 7279 |
2/2✓ Branch 0 taken 21 times.
✓ Branch 1 taken 1465507 times.
|
1465528 | if (key_info->secondary_engine_attribute.length > 0) |
| 7280 | 21 | key_info->flags |= HA_INDEX_USES_SECONDARY_ENGINE_ATTRIBUTE; | |
| 7281 | #ifndef NDEBUG | ||
| 7282 | 1465528 | decltype(key_info->flags) flags_before_switch = key_info->flags; | |
| 7283 | #endif /* NDEBUG */ | ||
| 7284 |
6/7✓ Branch 0 taken 510248 times.
✓ Branch 1 taken 2444 times.
✓ Branch 2 taken 1313 times.
✓ Branch 3 taken 951503 times.
✓ Branch 4 taken 19 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
|
1465528 | switch (static_cast<int>(key->type)) { |
| 7285 | 510248 | case KEYTYPE_MULTIPLE: | |
| 7286 | 510248 | break; | |
| 7287 | 2444 | case KEYTYPE_FULLTEXT: | |
| 7288 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2440 times.
|
2444 | if (!(file->ha_table_flags() & HA_CAN_FULLTEXT)) { |
| 7289 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | my_error(ER_TABLE_CANT_HANDLE_FT, MYF(0)); |
| 7290 | 4 | return true; | |
| 7291 | } | ||
| 7292 | 2440 | key_info->flags |= HA_FULLTEXT; | |
| 7293 |
2/2✓ Branch 0 taken 1169 times.
✓ Branch 1 taken 1271 times.
|
2440 | if (key->key_create_info.parser_name.str) { |
| 7294 | 1169 | key_info->parser_name = key->key_create_info.parser_name; | |
| 7295 | 1169 | key_info->flags |= HA_USES_PARSER; | |
| 7296 | } else | ||
| 7297 | 1271 | key_info->parser_name = NULL_CSTR; | |
| 7298 | 2440 | break; | |
| 7299 | 1313 | case KEYTYPE_SPATIAL: | |
| 7300 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1313 times.
|
1313 | if (!(file->ha_table_flags() & HA_CAN_RTREEKEYS)) { |
| 7301 | ✗ | my_error(ER_TABLE_CANT_HANDLE_SPKEYS, MYF(0)); | |
| 7302 | ✗ | return true; | |
| 7303 | } | ||
| 7304 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1309 times.
|
1313 | if (key->columns.size() != 1) { |
| 7305 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | my_error(ER_TOO_MANY_KEY_PARTS, MYF(0), 1); |
| 7306 | 4 | return true; | |
| 7307 | } | ||
| 7308 | 1309 | key_info->flags |= HA_SPATIAL; | |
| 7309 | 1309 | break; | |
| 7310 | 951503 | case KEYTYPE_PRIMARY: | |
| 7311 | case KEYTYPE_UNIQUE: | ||
| 7312 | 951503 | key_info->flags |= HA_NOSAME; | |
| 7313 | 951503 | break; | |
| 7314 | 19 | case KEYTYPE_CLUSTERING | KEYTYPE_UNIQUE: | |
| 7315 | case KEYTYPE_CLUSTERING | KEYTYPE_MULTIPLE: | ||
| 7316 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 18 times.
|
19 | if (thd->work_part_info) { |
| 7317 | 1 | partition_info *part_info = thd->work_part_info; | |
| 7318 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | List_iterator<partition_element> part_it(part_info->partitions); |
| 7319 | partition_element *part_elem; | ||
| 7320 | |||
| 7321 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | while ((part_elem = part_it++)) { |
| 7322 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (part_elem->subpartitions.elements) { |
| 7323 | ✗ | List_iterator<partition_element> sub_it(part_elem->subpartitions); | |
| 7324 | partition_element *subpart_elem; | ||
| 7325 | ✗ | while ((subpart_elem = sub_it++)) { | |
| 7326 | ✗ | if (unlikely(!ha_check_storage_engine_flag( | |
| 7327 | ✗ | subpart_elem->engine_type, | |
| 7328 | HTON_SUPPORTS_CLUSTERED_KEYS))) { | ||
| 7329 | ✗ | my_error( | |
| 7330 | ER_ILLEGAL_HA_CREATE_OPTION, MYF(0), | ||
| 7331 | ✗ | ha_resolve_storage_engine_name(subpart_elem->engine_type), | |
| 7332 | "CLUSTERING"); | ||
| 7333 | ✗ | return true; | |
| 7334 | } | ||
| 7335 | } | ||
| 7336 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | } else if (unlikely(!ha_check_storage_engine_flag( |
| 7337 | 1 | part_elem->engine_type, | |
| 7338 | HTON_SUPPORTS_CLUSTERED_KEYS))) { | ||
| 7339 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_ILLEGAL_HA_CREATE_OPTION, MYF(0), |
| 7340 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | ha_resolve_storage_engine_name(part_elem->engine_type), |
| 7341 | "CLUSTERING"); | ||
| 7342 | 1 | return true; | |
| 7343 | } | ||
| 7344 | } | ||
| 7345 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | } else if (unlikely(!ha_check_storage_engine_flag( |
| 7346 | 18 | file->ht, HTON_SUPPORTS_CLUSTERED_KEYS))) { | |
| 7347 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | my_error(ER_ILLEGAL_HA_CREATE_OPTION, MYF(0), |
| 7348 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | ha_resolve_storage_engine_name(file->ht), "CLUSTERING"); |
| 7349 | 18 | return true; | |
| 7350 | } | ||
| 7351 | ✗ | if (key->type & KEYTYPE_UNIQUE) | |
| 7352 | ✗ | key_info->flags = HA_NOSAME; | |
| 7353 | else | ||
| 7354 | ✗ | key_info->flags = 0; | |
| 7355 | ✗ | key_info->flags |= HA_CLUSTERING; | |
| 7356 | ✗ | break; | |
| 7357 | ✗ | case KEYTYPE_CLUSTERING: | |
| 7358 | ✗ | assert(0); | |
| 7359 | 1 | default: | |
| 7360 | 1 | assert(false); | |
| 7361 | return true; | ||
| 7362 | } | ||
| 7363 | // Verify that no bits set before switch have been cleared. | ||
| 7364 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1465500 times.
|
1465500 | assert((key_info->flags & flags_before_switch) == flags_before_switch); |
| 7365 |
2/2✓ Branch 0 taken 1446 times.
✓ Branch 1 taken 1464054 times.
|
1465500 | if (key->generated) key_info->flags |= HA_GENERATED_KEY; |
| 7366 | |||
| 7367 | 1465500 | key_info->algorithm = key->key_create_info.algorithm; | |
| 7368 | 1465500 | key_info->user_defined_key_parts = key->columns.size(); | |
| 7369 | 1465501 | key_info->actual_key_parts = key_info->user_defined_key_parts; | |
| 7370 | 1465501 | key_info->key_part = *key_part_info; | |
| 7371 | 1465501 | key_info->usable_key_parts = key_number; | |
| 7372 | 1465501 | key_info->is_algorithm_explicit = false; | |
| 7373 | 1465501 | key_info->is_visible = key->key_create_info.is_visible; | |
| 7374 | |||
| 7375 | /* | ||
| 7376 | Make SPATIAL to be RTREE by default | ||
| 7377 | SPATIAL only on BLOB or at least BINARY, this | ||
| 7378 | actually should be replaced by special GEOM type | ||
| 7379 | in near future when new frm file is ready | ||
| 7380 | checking for proper key parts number: | ||
| 7381 | */ | ||
| 7382 | |||
| 7383 |
2/2✓ Branch 0 taken 1309 times.
✓ Branch 1 taken 1464192 times.
|
1465501 | if (key_info->flags & HA_SPATIAL) { |
| 7384 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1309 times.
|
1309 | assert(!key->key_create_info.is_algorithm_explicit); |
| 7385 | 1309 | key_info->algorithm = HA_KEY_ALG_RTREE; | |
| 7386 |
2/2✓ Branch 0 taken 2440 times.
✓ Branch 1 taken 1461752 times.
|
1464192 | } else if (key_info->flags & HA_FULLTEXT) { |
| 7387 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2440 times.
|
2440 | assert(!key->key_create_info.is_algorithm_explicit); |
| 7388 | 2440 | key_info->algorithm = HA_KEY_ALG_FULLTEXT; | |
| 7389 | } else { | ||
| 7390 |
2/2✓ Branch 0 taken 60393 times.
✓ Branch 1 taken 1401359 times.
|
1461752 | if (key->key_create_info.is_algorithm_explicit) { |
| 7391 |
2/2✓ Branch 0 taken 60384 times.
✓ Branch 1 taken 9 times.
|
60393 | if (key->key_create_info.algorithm != HA_KEY_ALG_RTREE) { |
| 7392 | /* | ||
| 7393 | If key algorithm was specified explicitly check if it is | ||
| 7394 | supported by SE. | ||
| 7395 | */ | ||
| 7396 |
2/2✓ Branch 0 taken 371 times.
✓ Branch 1 taken 60013 times.
|
60384 | if (file->is_index_algorithm_supported( |
| 7397 |
1/2✓ Branch 0 taken 60384 times.
✗ Branch 1 not taken.
|
60384 | key->key_create_info.algorithm)) { |
| 7398 | 371 | key_info->is_algorithm_explicit = true; | |
| 7399 | 371 | key_info->algorithm = key->key_create_info.algorithm; | |
| 7400 | } else { | ||
| 7401 | /* | ||
| 7402 | If explicit algorithm is not supported by SE, replace it with | ||
| 7403 | default one. Don't mark key algorithm as explicitly specified | ||
| 7404 | in this case. | ||
| 7405 | */ | ||
| 7406 |
1/2✓ Branch 0 taken 60013 times.
✗ Branch 1 not taken.
|
60013 | key_info->algorithm = file->get_default_index_algorithm(); |
| 7407 | |||
| 7408 |
2/4✓ Branch 0 taken 60013 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 60014 times.
✗ Branch 3 not taken.
|
60013 | push_warning_printf( |
| 7409 | thd, Sql_condition::SL_NOTE, ER_UNSUPPORTED_INDEX_ALGORITHM, | ||
| 7410 | ER_THD(thd, ER_UNSUPPORTED_INDEX_ALGORITHM), | ||
| 7411 |
2/2✓ Branch 0 taken 59998 times.
✓ Branch 1 taken 15 times.
|
60013 | ((key->key_create_info.algorithm == HA_KEY_ALG_HASH) ? "HASH" |
| 7412 | : "BTREE")); | ||
| 7413 | } | ||
| 7414 | } | ||
| 7415 | } else { | ||
| 7416 | /* | ||
| 7417 | If key algorithm was not explicitly specified used default one for | ||
| 7418 | this SE. Interesting side-effect of this is that ALTER TABLE will | ||
| 7419 | cause index rebuild if SE default changes. | ||
| 7420 | Assert that caller doesn't use any non-default algorithm in this | ||
| 7421 | case as such setting is ignored anyway. | ||
| 7422 | */ | ||
| 7423 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1401359 times.
|
1401359 | assert(key->key_create_info.algorithm == HA_KEY_ALG_SE_SPECIFIC); |
| 7424 |
1/2✓ Branch 0 taken 1401358 times.
✗ Branch 1 not taken.
|
1401359 | key_info->algorithm = file->get_default_index_algorithm(); |
| 7425 | } | ||
| 7426 | } | ||
| 7427 | |||
| 7428 | /* | ||
| 7429 | Take block size from key part or table part | ||
| 7430 | TODO: Add warning if block size changes. We can't do it here, as | ||
| 7431 | this may depend on the size of the key | ||
| 7432 | */ | ||
| 7433 | 1465220 | key_info->block_size = | |
| 7434 |
2/2✓ Branch 0 taken 281 times.
✓ Branch 1 taken 1465220 times.
|
1465501 | (key->key_create_info.block_size ? key->key_create_info.block_size |
| 7435 | : create_info->key_block_size); | ||
| 7436 | |||
| 7437 |
2/2✓ Branch 0 taken 1121 times.
✓ Branch 1 taken 1464380 times.
|
1465501 | if (key_info->block_size) key_info->flags |= HA_USES_BLOCK_SIZE; |
| 7438 | |||
| 7439 | 1465501 | const CHARSET_INFO *ft_key_charset = nullptr; // for FULLTEXT | |
| 7440 | 1465501 | key_info->key_length = 0; | |
| 7441 |
2/2✓ Branch 0 taken 2332319 times.
✓ Branch 1 taken 1465210 times.
|
3797531 | for (size_t column_nr = 0; column_nr < key->columns.size(); |
| 7442 | 2332030 | column_nr++, (*key_part_info)++) { | |
| 7443 |
2/2✓ Branch 0 taken 290 times.
✓ Branch 1 taken 2332030 times.
|
2332320 | if (prepare_key_column(thd, create_info, create_list, key, |
| 7444 |
2/4✓ Branch 0 taken 2332320 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2332320 times.
✗ Branch 3 not taken.
|
2332319 | key->columns[column_nr], column_nr, key_info, |
| 7445 | *key_part_info, file, auto_increment, | ||
| 7446 | &ft_key_charset)) | ||
| 7447 | 290 | return true; | |
| 7448 | } | ||
| 7449 | 1465210 | key_info->actual_flags = key_info->flags; | |
| 7450 | |||
| 7451 |
5/6✓ Branch 0 taken 1465211 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 338 times.
✓ Branch 3 taken 1464873 times.
✓ Branch 4 taken 323 times.
✓ Branch 5 taken 1464888 times.
|
1465548 | if (key_info->key_length > file->max_key_length() && |
| 7452 |
2/2✓ Branch 0 taken 323 times.
✓ Branch 1 taken 15 times.
|
338 | key->type != KEYTYPE_FULLTEXT) { |
| 7453 |
2/4✓ Branch 0 taken 323 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 323 times.
✗ Branch 3 not taken.
|
323 | my_error(ER_TOO_LONG_KEY, MYF(0), file->max_key_length()); |
| 7454 |
3/4✓ Branch 0 taken 323 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 22 times.
✓ Branch 3 taken 301 times.
|
323 | if (thd->is_error()) // May be silenced - see Bug#20629014 |
| 7455 | 22 | return true; | |
| 7456 | } | ||
| 7457 | |||
| 7458 | /* | ||
| 7459 | We only check for duplicate indexes if it is requested and the key is | ||
| 7460 | not auto-generated and non-PRIMARY. | ||
| 7461 | |||
| 7462 | Check is requested if the key was explicitly created or altered | ||
| 7463 | (Index is altered/column associated with it is dropped) by the user | ||
| 7464 | (unless it's a foreign key). | ||
| 7465 | |||
| 7466 | The fact that we have only one PRIMARY key for the table is checked | ||
| 7467 | elsewhere. | ||
| 7468 | |||
| 7469 | At this point we simply add qualifying keys to the list, so we can | ||
| 7470 | perform check later when we properly construct KEY objects for all | ||
| 7471 | keys. | ||
| 7472 | */ | ||
| 7473 |
4/4✓ Branch 0 taken 1380532 times.
✓ Branch 1 taken 84657 times.
✓ Branch 2 taken 1379314 times.
✓ Branch 3 taken 1218 times.
|
1465189 | if (key->check_for_duplicate_indexes && !key->generated && |
| 7474 |
2/2✓ Branch 0 taken 929339 times.
✓ Branch 1 taken 449975 times.
|
1379314 | key->type != KEYTYPE_PRIMARY) { |
| 7475 |
2/4✓ Branch 0 taken 929339 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 929339 times.
|
929339 | if (keys_to_check.push_back(key_info)) return true; |
| 7476 | } | ||
| 7477 | 1465189 | return false; | |
| 7478 | 1466550 | } | |
| 7479 | |||
| 7480 | /** | ||
| 7481 | Primary/unique key check. Checks that: | ||
| 7482 | |||
| 7483 | - If the storage engine requires it, that there is an index that is | ||
| 7484 | candidate for promotion. | ||
| 7485 | |||
| 7486 | - If such a promotion occurs, checks that the candidate index is not | ||
| 7487 | declared invisible. | ||
| 7488 | |||
| 7489 | @param file The storage engine handler. | ||
| 7490 | @param key_info_buffer All indexes in the table. | ||
| 7491 | @param key_count Number of indexes. | ||
| 7492 | |||
| 7493 | @retval false OK. | ||
| 7494 | @retval true An error occurred and my_error() was called. | ||
| 7495 | */ | ||
| 7496 | |||
| 7497 | 247401 | static bool check_promoted_index(const handler *file, | |
| 7498 | const KEY *key_info_buffer, uint key_count) { | ||
| 7499 | 247401 | bool has_unique_key = false; | |
| 7500 | 247401 | const KEY *end = key_info_buffer + key_count; | |
| 7501 |
4/4✓ Branch 0 taken 114928 times.
✓ Branch 1 taken 223407 times.
✓ Branch 2 taken 90935 times.
✓ Branch 3 taken 23993 times.
|
338335 | for (const KEY *k = key_info_buffer; k < end && !has_unique_key; ++k) |
| 7502 |
4/4✓ Branch 0 taken 45929 times.
✓ Branch 1 taken 45006 times.
✓ Branch 2 taken 39169 times.
✓ Branch 3 taken 6760 times.
|
90935 | if (!(k->flags & HA_NULL_PART_KEY) && (k->flags & HA_NOSAME)) { |
| 7503 | 39169 | has_unique_key = true; | |
| 7504 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 39168 times.
|
39169 | if (!k->is_visible) { |
| 7505 | 1 | my_error(ER_PK_INDEX_CANT_BE_INVISIBLE, MYF(0)); | |
| 7506 | 1 | return true; | |
| 7507 | } | ||
| 7508 | } | ||
| 7509 |
4/6✓ Branch 0 taken 208245 times.
✓ Branch 1 taken 39155 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 208241 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 247396 times.
|
247400 | if (!has_unique_key && (file->ha_table_flags() & HA_REQUIRE_PRIMARY_KEY)) { |
| 7510 | ✗ | my_error(ER_REQUIRES_PRIMARY_KEY, MYF(0)); | |
| 7511 | ✗ | return true; | |
| 7512 | } | ||
| 7513 | 247396 | return false; | |
| 7514 | } | ||
| 7515 | |||
| 7516 | namespace { | ||
| 7517 | /** | ||
| 7518 | This class is used as an input argument to Item::walk, and takes care of | ||
| 7519 | replacing the field pointer in Item_field with pointers to a | ||
| 7520 | Create_field_wrapper. This allows us to get the metadata for a column that | ||
| 7521 | isn't created yet (Create_field). | ||
| 7522 | */ | ||
| 7523 | class Replace_field_processor_arg { | ||
| 7524 | public: | ||
| 7525 | 568 | Replace_field_processor_arg(THD *thd, List<Create_field> *fields, | |
| 7526 | const HA_CREATE_INFO *create_info, | ||
| 7527 | const char *functional_index_name) | ||
| 7528 | 568 | : m_thd(thd), | |
| 7529 | 568 | m_fields(fields), | |
| 7530 | 568 | m_create_info(create_info), | |
| 7531 | 568 | m_functional_index_name(functional_index_name) {} | |
| 7532 | |||
| 7533 | const HA_CREATE_INFO *create_info() const { return m_create_info; } | ||
| 7534 | |||
| 7535 | 628 | const THD *thd() const { return m_thd; } | |
| 7536 | |||
| 7537 | 631 | List<Create_field> const *fields() const { return m_fields; } | |
| 7538 | |||
| 7539 | ✗ | const char *functional_index_name() const { return m_functional_index_name; } | |
| 7540 | |||
| 7541 | private: | ||
| 7542 | THD *m_thd; | ||
| 7543 | List<Create_field> *m_fields; | ||
| 7544 | const HA_CREATE_INFO *m_create_info; | ||
| 7545 | const char *m_functional_index_name; | ||
| 7546 | }; | ||
| 7547 | } // namespace | ||
| 7548 | |||
| 7549 | 631 | bool Item_field::replace_field_processor(uchar *arg) { | |
| 7550 | Replace_field_processor_arg *targ = | ||
| 7551 | 631 | pointer_cast<Replace_field_processor_arg *>(arg); | |
| 7552 | |||
| 7553 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 631 times.
|
631 | if (field_name == nullptr) { |
| 7554 | // Ideally we should be able to handle the function DEFAULT() as well, | ||
| 7555 | // but that seems rather difficult since it relies on having a TABLE object | ||
| 7556 | // available (which we obviously don't have during CREATE TABLE). So | ||
| 7557 | // disallow that function for now. | ||
| 7558 | ✗ | assert(type() == Item::INSERT_VALUE_ITEM || | |
| 7559 | type() == Item::DEFAULT_VALUE_ITEM); | ||
| 7560 | ✗ | my_error(ER_FUNCTIONAL_INDEX_FUNCTION_IS_NOT_ALLOWED, MYF(0), | |
| 7561 | targ->functional_index_name()); | ||
| 7562 | ✗ | return true; | |
| 7563 | } | ||
| 7564 | |||
| 7565 | 631 | const Create_field *create_field = nullptr; | |
| 7566 |
5/8✓ Branch 0 taken 631 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 631 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1164 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1161 times.
✓ Branch 7 taken 3 times.
|
1164 | for (const Create_field &create_field_it : *targ->fields()) { |
| 7567 |
1/2✓ Branch 0 taken 1161 times.
✗ Branch 1 not taken.
|
1161 | if (my_strcasecmp(system_charset_info, field_name, |
| 7568 |
2/2✓ Branch 0 taken 628 times.
✓ Branch 1 taken 533 times.
|
1161 | create_field_it.field_name) == 0) { |
| 7569 | 628 | create_field = &create_field_it; | |
| 7570 | 628 | break; | |
| 7571 | } | ||
| 7572 | } | ||
| 7573 | |||
| 7574 |
2/2✓ Branch 0 taken 628 times.
✓ Branch 1 taken 3 times.
|
631 | if (create_field) { |
| 7575 |
2/4✓ Branch 0 taken 628 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 628 times.
✗ Branch 3 not taken.
|
628 | field = new (targ->thd()->mem_root) Create_field_wrapper(create_field); |
| 7576 |
15/16✓ Branch 0 taken 1 times.
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 5 times.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 295 times.
✓ Branch 9 taken 3 times.
✓ Branch 10 taken 1 times.
✓ Branch 11 taken 291 times.
✓ Branch 12 taken 1 times.
✓ Branch 13 taken 1 times.
✓ Branch 14 taken 2 times.
✗ Branch 15 not taken.
|
628 | switch (create_field->sql_type) { |
| 7577 | 1 | case MYSQL_TYPE_TINY_BLOB: | |
| 7578 | case MYSQL_TYPE_MEDIUM_BLOB: | ||
| 7579 | case MYSQL_TYPE_LONG_BLOB: | ||
| 7580 | case MYSQL_TYPE_BLOB: { | ||
| 7581 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | assert(create_field->charset != nullptr); |
| 7582 | 1 | set_data_type_string(blob_length_by_type(create_field->sql_type), | |
| 7583 | 1 | create_field->charset); | |
| 7584 | 1 | break; | |
| 7585 | } | ||
| 7586 | 20 | case MYSQL_TYPE_STRING: | |
| 7587 | case MYSQL_TYPE_VARCHAR: { | ||
| 7588 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
|
20 | assert(create_field->charset != nullptr); |
| 7589 | 20 | set_data_type_string(create_field->max_display_width_in_codepoints(), | |
| 7590 | 20 | create_field->charset); | |
| 7591 | 20 | break; | |
| 7592 | } | ||
| 7593 | 1 | case MYSQL_TYPE_NEWDECIMAL: { | |
| 7594 | 2 | uint precision = my_decimal_length_to_precision( | |
| 7595 | 1 | create_field->max_display_width_in_codepoints(), | |
| 7596 | 1 | create_field->decimals, create_field->is_unsigned); | |
| 7597 | 1 | set_data_type_decimal(precision, create_field->decimals); | |
| 7598 | 1 | break; | |
| 7599 | } | ||
| 7600 | 3 | case MYSQL_TYPE_DATETIME2: { | |
| 7601 | 3 | set_data_type_datetime(create_field->decimals); | |
| 7602 | 3 | break; | |
| 7603 | } | ||
| 7604 | 1 | case MYSQL_TYPE_TIMESTAMP2: { | |
| 7605 | 1 | set_data_type_timestamp(create_field->decimals); | |
| 7606 | 1 | break; | |
| 7607 | } | ||
| 7608 | 2 | case MYSQL_TYPE_NEWDATE: { | |
| 7609 | 2 | set_data_type_date(); | |
| 7610 | 2 | break; | |
| 7611 | } | ||
| 7612 | 5 | case MYSQL_TYPE_TIME2: { | |
| 7613 | 5 | set_data_type_time(create_field->decimals); | |
| 7614 | 5 | break; | |
| 7615 | } | ||
| 7616 | 1 | case MYSQL_TYPE_YEAR: { | |
| 7617 | 1 | set_data_type_year(); | |
| 7618 | 1 | break; | |
| 7619 | } | ||
| 7620 | 295 | case MYSQL_TYPE_INT24: | |
| 7621 | case MYSQL_TYPE_TINY: | ||
| 7622 | case MYSQL_TYPE_SHORT: | ||
| 7623 | case MYSQL_TYPE_LONG: | ||
| 7624 | case MYSQL_TYPE_LONGLONG: | ||
| 7625 | case MYSQL_TYPE_BIT: { | ||
| 7626 | 295 | fix_char_length(create_field->max_display_width_in_codepoints()); | |
| 7627 | 295 | set_data_type(create_field->sql_type); | |
| 7628 | 295 | collation.set_numeric(); | |
| 7629 | 295 | break; | |
| 7630 | } | ||
| 7631 | 3 | case MYSQL_TYPE_DOUBLE: { | |
| 7632 | 3 | set_data_type_double(); | |
| 7633 | 3 | decimals = create_field->decimals; | |
| 7634 | 3 | break; | |
| 7635 | } | ||
| 7636 | 1 | case MYSQL_TYPE_FLOAT: { | |
| 7637 | 1 | set_data_type_float(); | |
| 7638 | 1 | decimals = create_field->decimals; | |
| 7639 | 1 | break; | |
| 7640 | } | ||
| 7641 | 291 | case MYSQL_TYPE_JSON: { | |
| 7642 | 291 | set_data_type_json(); | |
| 7643 | 291 | break; | |
| 7644 | } | ||
| 7645 | 1 | case MYSQL_TYPE_GEOMETRY: { | |
| 7646 | 1 | set_data_type_geometry(); | |
| 7647 | 1 | break; | |
| 7648 | } | ||
| 7649 | 1 | case MYSQL_TYPE_ENUM: { | |
| 7650 | 1 | set_data_type(create_field->sql_type); | |
| 7651 | 1 | collation.collation = create_field->charset; | |
| 7652 | 1 | fix_char_length(create_field->max_display_width_in_codepoints()); | |
| 7653 | 1 | break; | |
| 7654 | } | ||
| 7655 | 2 | case MYSQL_TYPE_SET: { | |
| 7656 | 2 | set_data_type(create_field->sql_type); | |
| 7657 | 2 | collation.collation = create_field->charset; | |
| 7658 | 2 | fix_char_length(create_field->max_display_width_in_codepoints()); | |
| 7659 | 2 | break; | |
| 7660 | } | ||
| 7661 | ✗ | default: { | |
| 7662 | ✗ | assert(false); /* purecov: deadcode */ | |
| 7663 | } | ||
| 7664 | } | ||
| 7665 | |||
| 7666 | 628 | fixed = true; | |
| 7667 | } else { | ||
| 7668 | // If the field could not be found, it means that we have added a reference | ||
| 7669 | // to a non-existing field. Report an error and return. | ||
| 7670 | 3 | my_error(ER_BAD_FIELD_ERROR, MYF(0), field_name, "functional index"); | |
| 7671 | 3 | return true; | |
| 7672 | } | ||
| 7673 | |||
| 7674 |
4/4✓ Branch 0 taken 625 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 622 times.
|
1253 | unsigned_flag = create_field->sql_type == MYSQL_TYPE_BIT || |
| 7675 | 625 | field->is_flag_set(UNSIGNED_FLAG); | |
| 7676 | 628 | set_nullable(create_field->is_nullable); | |
| 7677 | 628 | field->field_length = max_length; | |
| 7678 | 628 | return false; | |
| 7679 | } | ||
| 7680 | |||
| 7681 | /** | ||
| 7682 | Check if the given key name exists in the array of keys. The lookup is | ||
| 7683 | case insensitive. | ||
| 7684 | |||
| 7685 | @param keys the array to check for the key name in | ||
| 7686 | @param key_name the key name to look for. | ||
| 7687 | @param key_to_ignore a pointer to the key we don't want to check against. This | ||
| 7688 | is used when checking for duplicate functional index names. | ||
| 7689 | |||
| 7690 | @retval true if the key name exists in the array | ||
| 7691 | @retval false if the key name doesn't exist in the array | ||
| 7692 | */ | ||
| 7693 | 175 | static bool key_name_exists(const Mem_root_array<Key_spec *> &keys, | |
| 7694 | const std::string &key_name, | ||
| 7695 | const Key_spec *key_to_ignore) { | ||
| 7696 |
2/2✓ Branch 0 taken 321 times.
✓ Branch 1 taken 130 times.
|
451 | for (Key_spec *key_spec : keys) { |
| 7697 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 321 times.
|
321 | if (key_spec == key_to_ignore) { |
| 7698 | ✗ | continue; | |
| 7699 | } | ||
| 7700 | |||
| 7701 |
4/4✓ Branch 0 taken 94 times.
✓ Branch 1 taken 227 times.
✓ Branch 2 taken 45 times.
✓ Branch 3 taken 276 times.
|
415 | if (key_spec->name.str != nullptr && |
| 7702 |
2/2✓ Branch 0 taken 45 times.
✓ Branch 1 taken 49 times.
|
94 | my_strcasecmp(system_charset_info, key_name.c_str(), |
| 7703 | key_spec->name.str) == 0) { | ||
| 7704 | 45 | return true; | |
| 7705 | } | ||
| 7706 | } | ||
| 7707 | |||
| 7708 | 130 | return false; | |
| 7709 | } | ||
| 7710 | |||
| 7711 | /// Checks if a column with the given name exists in a list of fields. | ||
| 7712 | 573 | static bool column_name_exists(const List<Create_field> &fields, | |
| 7713 | const string &column_name) { | ||
| 7714 |
5/8✓ Branch 0 taken 573 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 573 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2674 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2103 times.
✓ Branch 7 taken 571 times.
|
2674 | for (const Create_field &field : fields) { |
| 7715 |
1/2✓ Branch 0 taken 2103 times.
✗ Branch 1 not taken.
|
2103 | if (my_strcasecmp(system_charset_info, column_name.c_str(), |
| 7716 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2101 times.
|
2103 | field.field_name) == 0) { |
| 7717 | 2 | return true; | |
| 7718 | } | ||
| 7719 | } | ||
| 7720 | 571 | return false; | |
| 7721 | } | ||
| 7722 | |||
| 7723 | /** | ||
| 7724 | Create a name for the hidden generated column that represents the functional | ||
| 7725 | key part. | ||
| 7726 | |||
| 7727 | The name is a string on the form `!hidden!index_name!key_part!counter`. The | ||
| 7728 | counter is usually 0, but is incremented until a unique name is found, in the | ||
| 7729 | unlikely event that there is another column with the same name. The index_name | ||
| 7730 | part may be truncated to make sure the column name does not exceed the maximum | ||
| 7731 | column name length (NAME_CHAR_LEN). | ||
| 7732 | |||
| 7733 | @param key_name the name of the index. | ||
| 7734 | @param key_part_number the key part number, starting from zero. | ||
| 7735 | @param fields the other columns in the table | ||
| 7736 | @param mem_root the MEM_ROOT where the column name should be allocated. | ||
| 7737 | |||
| 7738 | @returns the name for the hidden generated column, allocated on the supplied | ||
| 7739 | MEM_ROOT | ||
| 7740 | */ | ||
| 7741 | 571 | static const char *make_functional_index_column_name( | |
| 7742 | std::string_view key_name, unsigned key_part_number, | ||
| 7743 | const List<Create_field> &fields, MEM_ROOT *mem_root) { | ||
| 7744 | // Loop until we have found a unique name. We'll usually find one in the first | ||
| 7745 | // iteration, but if there are user-defined columns using the same naming | ||
| 7746 | // scheme, we might need to increment the counter to avoid collisions. We're | ||
| 7747 | // guaranteed to find a unique name in at most fields.size() + 1 iterations. | ||
| 7748 | 571 | for (unsigned count = 0;; ++count) { | |
| 7749 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 573 times.
|
573 | assert(count <= fields.size()); |
| 7750 | |||
| 7751 |
1/2✓ Branch 0 taken 573 times.
✗ Branch 1 not taken.
|
573 | string name("!hidden!"); |
| 7752 |
1/2✓ Branch 0 taken 573 times.
✗ Branch 1 not taken.
|
573 | name += key_name; |
| 7753 | |||
| 7754 |
1/2✓ Branch 0 taken 573 times.
✗ Branch 1 not taken.
|
573 | string suffix("!"); |
| 7755 |
2/4✓ Branch 0 taken 573 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 573 times.
✗ Branch 3 not taken.
|
573 | suffix += to_string(key_part_number); |
| 7756 |
1/2✓ Branch 0 taken 573 times.
✗ Branch 1 not taken.
|
573 | suffix += '!'; |
| 7757 |
2/4✓ Branch 0 taken 573 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 573 times.
✗ Branch 3 not taken.
|
573 | suffix += to_string(count); |
| 7758 | |||
| 7759 | // If the name is so long that we hit the NAME_CHAR_LEN limit, truncate the | ||
| 7760 | // index name part, so that there is enough room to add the suffix with the | ||
| 7761 | // key part number and the counter. (If we had truncated the counter, we | ||
| 7762 | // could loop forever because the generated name is the same in each | ||
| 7763 | // iteration.) | ||
| 7764 |
1/2✓ Branch 0 taken 573 times.
✗ Branch 1 not taken.
|
573 | name.resize(min(name.size(), NAME_CHAR_LEN - suffix.size())); |
| 7765 |
1/2✓ Branch 0 taken 573 times.
✗ Branch 1 not taken.
|
573 | name.append(suffix); |
| 7766 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 573 times.
|
573 | assert(name.size() <= NAME_CHAR_LEN); |
| 7767 | |||
| 7768 |
3/4✓ Branch 0 taken 573 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 571 times.
|
573 | if (column_name_exists(fields, name)) { |
| 7769 | 2 | continue; | |
| 7770 | } | ||
| 7771 | |||
| 7772 |
1/2✓ Branch 0 taken 571 times.
✗ Branch 1 not taken.
|
1142 | return strmake_root(mem_root, name.data(), name.size()); |
| 7773 |
4/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 571 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 571 times.
|
1146 | } |
| 7774 | } | ||
| 7775 | |||
| 7776 | /** | ||
| 7777 | Whether or not we have a replication setup, _and_ the master sorts | ||
| 7778 | functional index columns last in the table. Sorting said columns last was | ||
| 7779 | introduced in version 8.0.18, and this function helps us keep consistent | ||
| 7780 | behavior in a OLD->NEW replication setup. | ||
| 7781 | |||
| 7782 | @returns false if we have a replication setup, _and_ the server is on a old | ||
| 7783 | version that doesn't sort functional index columns last. | ||
| 7784 | */ | ||
| 7785 | 875 | static bool is_not_slave_or_master_sorts_functional_index_columns_last( | |
| 7786 | uint32_t master_version) { | ||
| 7787 | // From version 8.0.18, the server will sort functional index columns last in | ||
| 7788 | // the table. | ||
| 7789 |
3/4✓ Branch 0 taken 873 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 873 times.
✗ Branch 3 not taken.
|
875 | return master_version >= 80018 && master_version != UNKNOWN_SERVER_VERSION; |
| 7790 | } | ||
| 7791 | |||
| 7792 | /** | ||
| 7793 | Prepares a functional index by adding a hidden indexed generated column for | ||
| 7794 | the key part. | ||
| 7795 | |||
| 7796 | A functional index is implemented as a hidden generated column over the | ||
| 7797 | expression specified in the index, and the hidden generated column is then | ||
| 7798 | indexed. This function adds a hidden generated column to the Create_list, | ||
| 7799 | and updates the key specification to point to this new column. The generated | ||
| 7800 | column is given a name that is a hash of the key name and the key part number. | ||
| 7801 | |||
| 7802 | @param thd The thread handler | ||
| 7803 | @param key_spec The index that contains the key part.- | ||
| 7804 | @param alter_info A structure describing the changes to be carried out. This | ||
| 7805 | structure will be updated with the new generated column. | ||
| 7806 | @param kp The specification of the key part. This contains the expression we | ||
| 7807 | will create a generated column for, and it will be updated to point | ||
| 7808 | at the newly created generated column. | ||
| 7809 | @param key_part_number The number of the key part. | ||
| 7810 | @param create_info A structure describing the table to be created | ||
| 7811 | |||
| 7812 | @returns The newly added Create_field on success, of nullptr in case of errors | ||
| 7813 | */ | ||
| 7814 | 586 | static Create_field *add_functional_index_to_create_list( | |
| 7815 | THD *thd, Key_spec *key_spec, Alter_info *alter_info, Key_part_spec *kp, | ||
| 7816 | uint key_part_number, HA_CREATE_INFO *create_info) { | ||
| 7817 | // A functional index cannot be a primary key | ||
| 7818 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 580 times.
|
586 | if (key_spec->type == KEYTYPE_PRIMARY) { |
| 7819 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | my_error(ER_FUNCTIONAL_INDEX_PRIMARY_KEY, MYF(0)); |
| 7820 | 6 | return nullptr; | |
| 7821 | } | ||
| 7822 | |||
| 7823 | // If the key isn't given a name explicitly by the user, we must auto-generate | ||
| 7824 | // a name here. "Normal" indexes will be given a name in prepare_key(), but | ||
| 7825 | // that is too late for functional indexes since we want the hidden generated | ||
| 7826 | // column name to be based on the index name. | ||
| 7827 |
2/2✓ Branch 0 taken 130 times.
✓ Branch 1 taken 450 times.
|
580 | if (key_spec->name.str == nullptr) { |
| 7828 | 130 | std::string key_name; | |
| 7829 | 130 | int count = 2; | |
| 7830 |
1/2✓ Branch 0 taken 130 times.
✗ Branch 1 not taken.
|
130 | key_name.assign("functional_index"); |
| 7831 |
3/4✓ Branch 0 taken 175 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 45 times.
✓ Branch 3 taken 130 times.
|
175 | while (key_name_exists(alter_info->key_list, key_name, nullptr)) { |
| 7832 |
1/2✓ Branch 0 taken 45 times.
✗ Branch 1 not taken.
|
45 | key_name.assign("functional_index_"); |
| 7833 |
2/4✓ Branch 0 taken 45 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 45 times.
✗ Branch 3 not taken.
|
45 | key_name.append(std::to_string(count++)); |
| 7834 | } | ||
| 7835 | |||
| 7836 | 130 | key_spec->name.length = key_name.size(); | |
| 7837 |
1/2✓ Branch 0 taken 130 times.
✗ Branch 1 not taken.
|
130 | key_spec->name.str = strmake_root(thd->stmt_arena->mem_root, |
| 7838 | key_name.c_str(), key_name.size()); | ||
| 7839 | 130 | } | |
| 7840 | |||
| 7841 | // First we need to resolve the expression in the functional index so that we | ||
| 7842 | // know the correct collation, data type, length etc... | ||
| 7843 | 580 | ulong saved_privilege = thd->want_privilege; | |
| 7844 | 580 | thd->want_privilege = SELECT_ACL; | |
| 7845 | |||
| 7846 | { | ||
| 7847 | // Create a scope guard so that we are guaranteed that the privileges are | ||
| 7848 | // set back to the original value. | ||
| 7849 | auto handler_guard = create_scope_guard( | ||
| 7850 |
1/2✓ Branch 0 taken 580 times.
✗ Branch 1 not taken.
|
580 | [thd, saved_privilege]() { thd->want_privilege = saved_privilege; }); |
| 7851 | |||
| 7852 | Functional_index_error_handler error_handler( | ||
| 7853 |
2/4✓ Branch 0 taken 580 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 580 times.
✗ Branch 3 not taken.
|
1160 | {key_spec->name.str, key_spec->name.length}, thd); |
| 7854 | |||
| 7855 |
1/2✓ Branch 0 taken 580 times.
✗ Branch 1 not taken.
|
580 | Item *expr = kp->get_expression(); |
| 7856 |
3/4✓ Branch 0 taken 580 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 576 times.
|
580 | if (expr->type() == Item::FIELD_ITEM) { |
| 7857 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | my_error(ER_FUNCTIONAL_INDEX_ON_FIELD, MYF(0)); |
| 7858 | 4 | return nullptr; | |
| 7859 | } | ||
| 7860 | |||
| 7861 |
4/6✓ Branch 0 taken 576 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 576 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 568 times.
|
576 | if (pre_validate_value_generator_expr( |
| 7862 | kp->get_expression(), key_spec->name.str, VGS_GENERATED_COLUMN)) { | ||
| 7863 | 8 | return nullptr; | |
| 7864 | } | ||
| 7865 | |||
| 7866 | Replace_field_processor_arg replace_field_argument( | ||
| 7867 | 568 | thd, &alter_info->create_list, create_info, key_spec->name.str); | |
| 7868 |
3/4✓ Branch 0 taken 568 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 565 times.
|
568 | if (expr->walk(&Item::replace_field_processor, enum_walk::PREFIX, |
| 7869 | reinterpret_cast<uchar *>(&replace_field_argument))) { | ||
| 7870 | 3 | return nullptr; | |
| 7871 | } | ||
| 7872 | |||
| 7873 |
3/4✓ Branch 0 taken 565 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 562 times.
|
565 | if (kp->resolve_expression(thd)) return nullptr; |
| 7874 |
4/4✓ Branch 0 taken 562 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 562 times.
✓ Branch 3 taken 18 times.
|
598 | } |
| 7875 | |||
| 7876 |
1/2✓ Branch 0 taken 562 times.
✗ Branch 1 not taken.
|
562 | const char *field_name = make_functional_index_column_name( |
| 7877 | {key_spec->name.str, key_spec->name.length}, key_part_number, | ||
| 7878 | 562 | alter_info->create_list, thd->stmt_arena->mem_root); | |
| 7879 | |||
| 7880 |
1/2✓ Branch 0 taken 562 times.
✗ Branch 1 not taken.
|
562 | Item *item = kp->get_expression(); |
| 7881 | |||
| 7882 | // Ensure that we aren't trying to index a field | ||
| 7883 |
2/4✓ Branch 0 taken 562 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 562 times.
|
562 | assert(item->type() != Item::FIELD_ITEM); |
| 7884 | |||
| 7885 |
1/2✓ Branch 0 taken 562 times.
✗ Branch 1 not taken.
|
562 | TABLE tmp_table; |
| 7886 |
1/2✓ Branch 0 taken 562 times.
✗ Branch 1 not taken.
|
562 | TABLE_SHARE share; |
| 7887 | 562 | tmp_table.s = &share; | |
| 7888 |
1/2✓ Branch 0 taken 562 times.
✗ Branch 1 not taken.
|
562 | init_tmp_table_share(thd, &share, "", 0, "", "", nullptr); |
| 7889 | |||
| 7890 | 562 | tmp_table.s->db_create_options = 0; | |
| 7891 | 562 | tmp_table.s->db_low_byte_first = false; | |
| 7892 | 562 | tmp_table.set_not_started(); | |
| 7893 | |||
| 7894 |
1/2✓ Branch 0 taken 562 times.
✗ Branch 1 not taken.
|
562 | Create_field *cr = generate_create_field(thd, item, &tmp_table); |
| 7895 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 562 times.
|
562 | if (cr == nullptr) { |
| 7896 | ✗ | return nullptr; /* purecov: deadcode */ | |
| 7897 | } | ||
| 7898 | |||
| 7899 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 561 times.
|
562 | if (is_blob(cr->sql_type)) { |
| 7900 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_FUNCTIONAL_INDEX_ON_LOB, MYF(0)); |
| 7901 | 1 | return nullptr; | |
| 7902 | } | ||
| 7903 | |||
| 7904 | 561 | cr->field_name = field_name; | |
| 7905 | 561 | cr->field = nullptr; | |
| 7906 | 561 | cr->hidden = dd::Column::enum_hidden_type::HT_HIDDEN_SQL; | |
| 7907 | 561 | cr->stored_in_db = false; | |
| 7908 | |||
| 7909 |
1/2✓ Branch 0 taken 561 times.
✗ Branch 1 not taken.
|
1122 | Value_generator *gcol_info = new (thd->mem_root) Value_generator(); |
| 7910 |
1/2✓ Branch 0 taken 561 times.
✗ Branch 1 not taken.
|
561 | gcol_info->expr_item = kp->get_expression(); |
| 7911 | 561 | gcol_info->set_field_stored(false); | |
| 7912 | 561 | gcol_info->set_field_type(cr->sql_type); | |
| 7913 | 561 | cr->gcol_info = gcol_info; | |
| 7914 | |||
| 7915 |
2/2✓ Branch 0 taken 560 times.
✓ Branch 1 taken 1 times.
|
561 | if (is_not_slave_or_master_sorts_functional_index_columns_last( |
| 7916 | thd->variables.original_server_version)) { | ||
| 7917 | // Ensure that we insert the new hidden column in the correct place. That | ||
| 7918 | // is, hidden generated columns for functional indexes should be placed at | ||
| 7919 | // the end, sorted on their column name. | ||
| 7920 |
1/2✓ Branch 0 taken 560 times.
✗ Branch 1 not taken.
|
560 | List_iterator<Create_field> insert_iterator(alter_info->create_list); |
| 7921 |
5/8✓ Branch 0 taken 560 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 560 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2522 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2006 times.
✓ Branch 7 taken 516 times.
|
2522 | for (const Create_field ¤t : alter_info->create_list) { |
| 7922 |
3/4✓ Branch 0 taken 2006 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 383 times.
✓ Branch 3 taken 1623 times.
|
2006 | if (is_field_for_functional_index(¤t)) { |
| 7923 |
1/2✓ Branch 0 taken 383 times.
✗ Branch 1 not taken.
|
383 | if (my_strcasecmp(system_charset_info, cr->field_name, |
| 7924 |
2/2✓ Branch 0 taken 44 times.
✓ Branch 1 taken 339 times.
|
383 | current.field_name) < 0) { |
| 7925 | 44 | break; | |
| 7926 | } | ||
| 7927 | } | ||
| 7928 | |||
| 7929 | 1962 | insert_iterator++; | |
| 7930 | } | ||
| 7931 | |||
| 7932 | // insert_iterator points to the last element where the field name is | ||
| 7933 | // "less than" the new Create_fields field name. So the correct place to | ||
| 7934 | // insert the new Create_field is _after_ the element that insert_iterator | ||
| 7935 | // points to. | ||
| 7936 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 560 times.
|
560 | assert(!insert_iterator.is_before_first()); |
| 7937 |
1/2✓ Branch 0 taken 560 times.
✗ Branch 1 not taken.
|
560 | insert_iterator.after(cr); |
| 7938 | } else { | ||
| 7939 | // If the master doesn't sort functional index columns last, the slave | ||
| 7940 | // shouldn't do it either. | ||
| 7941 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | alter_info->create_list.push_back(cr); |
| 7942 | } | ||
| 7943 | |||
| 7944 | 561 | alter_info->flags |= Alter_info::ALTER_ADD_COLUMN; | |
| 7945 |
1/2✓ Branch 0 taken 561 times.
✗ Branch 1 not taken.
|
561 | kp->set_name_and_prefix_length(field_name, 0); |
| 7946 | 561 | return cr; | |
| 7947 | 562 | } | |
| 7948 | |||
| 7949 | /** | ||
| 7950 | Check if the given column exists in the create list. | ||
| 7951 | |||
| 7952 | @param column_name the column name to look for. | ||
| 7953 | @param create_list the create list where the search is performed. | ||
| 7954 | |||
| 7955 | @retval true the column exists in the create list. | ||
| 7956 | @retval false the column does not exist in the create list. | ||
| 7957 | */ | ||
| 7958 | 309 | static bool column_exists_in_create_list(const char *column_name, | |
| 7959 | List<Create_field> &create_list) { | ||
| 7960 |
4/8✓ Branch 0 taken 309 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 309 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2596 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2596 times.
✗ Branch 7 not taken.
|
2596 | for (const auto &it : create_list) { |
| 7961 |
3/4✓ Branch 0 taken 2596 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 309 times.
✓ Branch 3 taken 2287 times.
|
2596 | if (my_strcasecmp(system_charset_info, column_name, it.field_name) == 0) { |
| 7962 | 309 | return true; | |
| 7963 | } | ||
| 7964 | } | ||
| 7965 | ✗ | return false; | |
| 7966 | } | ||
| 7967 | |||
| 7968 | // Prepares the table and key structures for table creation. | ||
| 7969 | 756937 | bool mysql_prepare_create_table( | |
| 7970 | THD *thd, const char *error_schema_name, const char *error_table_name, | ||
| 7971 | HA_CREATE_INFO *create_info, Alter_info *alter_info, handler *file, | ||
| 7972 | bool is_partitioned, KEY **key_info_buffer, uint *key_count, | ||
| 7973 | FOREIGN_KEY **fk_key_info_buffer, uint *fk_key_count, | ||
| 7974 | FOREIGN_KEY *existing_fks, uint existing_fks_count, | ||
| 7975 | const dd::Table *existing_fks_table, uint fk_max_generated_name_number, | ||
| 7976 | int select_field_count, bool find_parent_keys) { | ||
| 7977 |
1/2✓ Branch 0 taken 756943 times.
✗ Branch 1 not taken.
|
756937 | DBUG_TRACE; |
| 7978 | |||
| 7979 | /* | ||
| 7980 | Validation of table properties. | ||
| 7981 | */ | ||
| 7982 | 756943 | LEX_STRING *connect_string = &create_info->connect_string; | |
| 7983 | 1513967 | if (connect_string->length != 0 && | |
| 7984 |
4/6✓ Branch 0 taken 81 times.
✓ Branch 1 taken 756862 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 81 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 756943 times.
|
756943 | connect_string->length > CONNECT_STRING_MAXLEN && |
| 7985 | ✗ | (system_charset_info->cset->charpos( | |
| 7986 | ✗ | system_charset_info, connect_string->str, | |
| 7987 | ✗ | (connect_string->str + connect_string->length), | |
| 7988 | ✗ | CONNECT_STRING_MAXLEN) < connect_string->length)) { | |
| 7989 | ✗ | my_error(ER_WRONG_STRING_LENGTH, MYF(0), connect_string->str, "CONNECTION", | |
| 7990 | CONNECT_STRING_MAXLEN); | ||
| 7991 | ✗ | return true; | |
| 7992 | } | ||
| 7993 | |||
| 7994 | 756943 | LEX_STRING *compress = &create_info->compress; | |
| 7995 |
6/6✓ Branch 0 taken 272 times.
✓ Branch 1 taken 756671 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 270 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 756941 times.
|
756945 | if (compress->length != 0 && compress->length > TABLE_COMMENT_MAXLEN && |
| 7996 | 4 | system_charset_info->cset->charpos( | |
| 7997 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | system_charset_info, compress->str, compress->str + compress->length, |
| 7998 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | TABLE_COMMENT_MAXLEN) < compress->length) { |
| 7999 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | my_error(ER_WRONG_STRING_LENGTH, MYF(0), compress->str, "COMPRESSION", |
| 8000 | TABLE_COMMENT_MAXLEN); | ||
| 8001 | 2 | return true; | |
| 8002 | } | ||
| 8003 | |||
| 8004 | 756941 | LEX_STRING *encrypt_type = &create_info->encrypt_type; | |
| 8005 | 1599181 | if (encrypt_type->length != 0 && | |
| 8006 |
4/6✓ Branch 0 taken 85299 times.
✓ Branch 1 taken 671642 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 85299 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 756941 times.
|
756941 | encrypt_type->length > TABLE_COMMENT_MAXLEN && |
| 8007 | ✗ | system_charset_info->cset->charpos( | |
| 8008 | ✗ | system_charset_info, encrypt_type->str, | |
| 8009 | ✗ | encrypt_type->str + encrypt_type->length, | |
| 8010 | ✗ | TABLE_COMMENT_MAXLEN) < encrypt_type->length) { | |
| 8011 | ✗ | my_error(ER_WRONG_STRING_LENGTH, MYF(0), encrypt_type->str, "ENCRYPTION", | |
| 8012 | TABLE_COMMENT_MAXLEN); | ||
| 8013 | ✗ | return true; | |
| 8014 | } | ||
| 8015 | |||
| 8016 | // Validate table comment string | ||
| 8017 | 756941 | std::string invalid_sub_str; | |
| 8018 |
3/4✓ Branch 0 taken 756932 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 756931 times.
|
756934 | if (is_invalid_string({create_info->comment.str, create_info->comment.length}, |
| 8019 | system_charset_info, invalid_sub_str)) { | ||
| 8020 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
2 | my_error( |
| 8021 | ER_COMMENT_CONTAINS_INVALID_STRING, MYF(0), "table", | ||
| 8022 |
4/8✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
|
2 | (std::string(error_schema_name) + "." + std::string(error_table_name)) |
| 8023 | .c_str(), | ||
| 8024 | system_charset_info->csname, invalid_sub_str.c_str()); | ||
| 8025 | 1 | return true; | |
| 8026 | } | ||
| 8027 | |||
| 8028 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 756928 times.
|
756932 | if (validate_comment_length( |
| 8029 |
1/2✓ Branch 0 taken 756932 times.
✗ Branch 1 not taken.
|
756931 | thd, create_info->comment.str, &create_info->comment.length, |
| 8030 | TABLE_COMMENT_MAXLEN, ER_TOO_LONG_TABLE_COMMENT, error_table_name)) { | ||
| 8031 | 4 | return true; | |
| 8032 | } | ||
| 8033 | |||
| 8034 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 756921 times.
|
756928 | if (alter_info->create_list.elements > MAX_FIELDS) { |
| 8035 |
1/2✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 | my_error(ER_TOO_MANY_FIELDS, MYF(0)); |
| 8036 | 7 | return true; | |
| 8037 | } | ||
| 8038 | |||
| 8039 | /* | ||
| 8040 | Checks which previously were done during .FRM creation. | ||
| 8041 | |||
| 8042 | TODO: Check if the old .FRM limitations still make sense | ||
| 8043 | with the new DD. | ||
| 8044 | */ | ||
| 8045 | |||
| 8046 | /* Fix this when we have new .frm files; Current limit is 4G rows (QQ) */ | ||
| 8047 | 756921 | constexpr ulonglong u32max = UINT_MAX32; | |
| 8048 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 756918 times.
|
756921 | if (create_info->max_rows > UINT_MAX32) { |
| 8049 | // Values larger than uint32_max are capped to uint32_max. | ||
| 8050 | // Emit a warning about this. | ||
| 8051 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | push_warning_printf(thd, Sql_condition::SL_WARNING, ER_VALUE_OUT_OF_RANGE, |
| 8052 | ER_THD(thd, ER_VALUE_OUT_OF_RANGE), "max_rows", | ||
| 8053 | create_info->max_rows, 0ULL, u32max, u32max); | ||
| 8054 | 3 | create_info->max_rows = UINT_MAX32; | |
| 8055 | } | ||
| 8056 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 756920 times.
|
756921 | if (create_info->min_rows > UINT_MAX32) { |
| 8057 | // Values larger than uint32_max are capped to uint32_max. | ||
| 8058 | // Emit a warning about this. | ||
| 8059 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | push_warning_printf(thd, Sql_condition::SL_WARNING, ER_VALUE_OUT_OF_RANGE, |
| 8060 | ER_THD(thd, ER_VALUE_OUT_OF_RANGE), "min_rows", | ||
| 8061 | create_info->min_rows, 0ULL, u32max, u32max); | ||
| 8062 | 1 | create_info->min_rows = UINT_MAX32; | |
| 8063 | } | ||
| 8064 | |||
| 8065 |
2/2✓ Branch 0 taken 439295 times.
✓ Branch 1 taken 317626 times.
|
756921 | if (create_info->row_type == ROW_TYPE_DYNAMIC) |
| 8066 | 439295 | create_info->table_options |= HA_OPTION_PACK_RECORD; | |
| 8067 | |||
| 8068 | /* | ||
| 8069 | Prepare fields, which must be done before calling | ||
| 8070 | add_functional_index_to_create_list(). The reason is that | ||
| 8071 | prepare_create_field() sets several properties of all Create_fields, such as | ||
| 8072 | character set. We need the character set in order to get the correct | ||
| 8073 | display width for each Create_field, which is in turn needed to resolve the | ||
| 8074 | correct data type/length for each hidden generated column added by | ||
| 8075 | add_functional_index_to_create_list(). | ||
| 8076 | */ | ||
| 8077 | 756921 | int select_field_pos = alter_info->create_list.elements - select_field_count; | |
| 8078 | 756921 | create_info->null_bits = 0; | |
| 8079 | 756921 | int field_no = 0; | |
| 8080 | Create_field *sql_field; | ||
| 8081 |
1/2✓ Branch 0 taken 756921 times.
✗ Branch 1 not taken.
|
756921 | List_iterator<Create_field> it(alter_info->create_list); |
| 8082 |
2/2✓ Branch 0 taken 6357202 times.
✓ Branch 1 taken 749507 times.
|
7106700 | for (; (sql_field = it++); field_no++) { |
| 8083 |
3/4✓ Branch 0 taken 6357191 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7412 times.
✓ Branch 3 taken 6349779 times.
|
6357202 | if (prepare_create_field(thd, error_schema_name, error_table_name, |
| 8084 | create_info, &alter_info->create_list, | ||
| 8085 | &select_field_pos, file, sql_field, field_no)) | ||
| 8086 | 7412 | return true; | |
| 8087 | } | ||
| 8088 | |||
| 8089 | // Go through all functional key parts. For each functional key part, resolve | ||
| 8090 | // the expression and add a hidden generated column to the create list. | ||
| 8091 |
2/2✓ Branch 0 taken 2691277 times.
✓ Branch 1 taken 749481 times.
|
3440759 | for (Key_spec *key : alter_info->key_list) { |
| 8092 |
2/2✓ Branch 0 taken 612882 times.
✓ Branch 1 taken 2078395 times.
|
2691277 | if (key->type == KEYTYPE_FOREIGN) continue; |
| 8093 | |||
| 8094 |
2/2✓ Branch 0 taken 2946310 times.
✓ Branch 1 taken 2078370 times.
|
5024680 | for (size_t j = 0; j < key->columns.size(); ++j) { |
| 8095 |
1/2✓ Branch 0 taken 2946310 times.
✗ Branch 1 not taken.
|
2946310 | Key_part_spec *key_part_spec = key->columns[j]; |
| 8096 | // In the case of procedures, the Key_part_spec may both have an | ||
| 8097 | // expression and a field name assigned to it. But the hidden generated | ||
| 8098 | // will not exist in the create list, so we will have to add it. | ||
| 8099 |
6/6✓ Branch 0 taken 895 times.
✓ Branch 1 taken 2945415 times.
✓ Branch 2 taken 309 times.
✓ Branch 3 taken 586 times.
✓ Branch 4 taken 2945724 times.
✓ Branch 5 taken 586 times.
|
2947514 | if (!key_part_spec->has_expression() || |
| 8100 | 895 | (key_part_spec->get_field_name() != nullptr && | |
| 8101 |
2/4✓ Branch 0 taken 309 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 309 times.
✗ Branch 3 not taken.
|
309 | column_exists_in_create_list(key_part_spec->get_field_name(), |
| 8102 | 309 | alter_info->create_list))) { | |
| 8103 | 2945724 | continue; | |
| 8104 | } | ||
| 8105 | |||
| 8106 |
1/2✓ Branch 0 taken 586 times.
✗ Branch 1 not taken.
|
586 | Create_field *new_create_field = add_functional_index_to_create_list( |
| 8107 | thd, key, alter_info, key_part_spec, j, create_info); | ||
| 8108 |
2/2✓ Branch 0 taken 25 times.
✓ Branch 1 taken 561 times.
|
586 | if (new_create_field == nullptr) { |
| 8109 | 25 | return true; | |
| 8110 | } | ||
| 8111 | |||
| 8112 | // Call prepare_create_field on the Create_field that was added by | ||
| 8113 | // add_functional_index_to_create_list(). | ||
| 8114 |
2/4✓ Branch 0 taken 561 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 561 times.
|
561 | assert(is_field_for_functional_index(new_create_field)); |
| 8115 |
2/4✓ Branch 0 taken 561 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 561 times.
|
561 | if (prepare_create_field(thd, error_schema_name, error_table_name, |
| 8116 | create_info, &alter_info->create_list, | ||
| 8117 | &select_field_pos, file, new_create_field, | ||
| 8118 | ++field_no)) { | ||
| 8119 | ✗ | return true; | |
| 8120 | } | ||
| 8121 | } | ||
| 8122 | } | ||
| 8123 | |||
| 8124 | // Now that we have all the Create_fields available, calculate the offsets | ||
| 8125 | // for each column. | ||
| 8126 |
1/2✓ Branch 0 taken 749488 times.
✗ Branch 1 not taken.
|
749481 | calculate_field_offsets(&alter_info->create_list); |
| 8127 | |||
| 8128 | /* | ||
| 8129 | Auto increment and blob checks. | ||
| 8130 | */ | ||
| 8131 | 749488 | int auto_increment = 0; | |
| 8132 | 749488 | int blob_columns = 0; | |
| 8133 | 749488 | it.rewind(); | |
| 8134 |
2/2✓ Branch 0 taken 6142801 times.
✓ Branch 1 taken 749483 times.
|
6892287 | while ((sql_field = it++)) { |
| 8135 | /* | ||
| 8136 | Check if the column is compressible. | ||
| 8137 | VIRTUAL generated columns cannot have COMPRESSED attribute. | ||
| 8138 | */ | ||
| 8139 | 18423799 | if ((sql_field->sql_type == MYSQL_TYPE_TINY_BLOB || | |
| 8140 |
2/2✓ Branch 0 taken 5771565 times.
✓ Branch 1 taken 366632 times.
|
6138197 | sql_field->sql_type == MYSQL_TYPE_MEDIUM_BLOB || |
| 8141 |
2/2✓ Branch 0 taken 5560327 times.
✓ Branch 1 taken 211238 times.
|
5771565 | sql_field->sql_type == MYSQL_TYPE_BLOB || |
| 8142 |
2/2✓ Branch 0 taken 5382600 times.
✓ Branch 1 taken 177727 times.
|
5560327 | sql_field->sql_type == MYSQL_TYPE_LONG_BLOB || |
| 8143 |
2/2✓ Branch 0 taken 4216241 times.
✓ Branch 1 taken 1166359 times.
|
5382600 | sql_field->sql_type == MYSQL_TYPE_VARCHAR || |
| 8144 |
6/6✓ Branch 0 taken 6138197 times.
✓ Branch 1 taken 4604 times.
✓ Branch 2 taken 106105 times.
✓ Branch 3 taken 4110136 times.
✓ Branch 4 taken 2028816 times.
✓ Branch 5 taken 4113985 times.
|
12391707 | sql_field->sql_type == MYSQL_TYPE_JSON) && |
| 8145 |
4/4✓ Branch 0 taken 5113 times.
✓ Branch 1 taken 2027552 times.
✓ Branch 2 taken 1264 times.
✓ Branch 3 taken 3849 times.
|
2037778 | (sql_field->gcol_info == nullptr || |
| 8146 | 5113 | sql_field->gcol_info->get_field_stored())) { | |
| 8147 |
2/4✓ Branch 0 taken 2028816 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2028816 times.
|
2028816 | DBUG_EXECUTE_IF( |
| 8148 | "enforce_all_compressed_columns", | ||
| 8149 | sql_field->set_column_format(COLUMN_FORMAT_TYPE_COMPRESSED);); | ||
| 8150 | |||
| 8151 | } else { | ||
| 8152 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4113972 times.
|
4113985 | if (sql_field->column_format() == COLUMN_FORMAT_TYPE_COMPRESSED) { |
| 8153 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | my_error(ER_UNSUPPORTED_COMPRESSED_COLUMN_TYPE, MYF(0), |
| 8154 | sql_field->field_name); | ||
| 8155 | 4 | return true; | |
| 8156 | } | ||
| 8157 | } | ||
| 8158 | |||
| 8159 | /* Verify if the compression dictionary entry exists. Open compression | ||
| 8160 | dictionary table with MDL_SHARED_READ mode. If the entry exists, | ||
| 8161 | do not release the MDL lock. This is because we don't want a concurrent | ||
| 8162 | DROP COMPRESSION_DICTIONARY to remove the dictionary entry | ||
| 8163 | */ | ||
| 8164 | |||
| 8165 | 6142788 | if (sql_field->column_format() == COLUMN_FORMAT_TYPE_COMPRESSED && | |
| 8166 |
6/6✓ Branch 0 taken 414 times.
✓ Branch 1 taken 6142381 times.
✓ Branch 2 taken 340 times.
✓ Branch 3 taken 74 times.
✓ Branch 4 taken 340 times.
✓ Branch 5 taken 6142455 times.
|
6143135 | sql_field->zip_dict_name.str != nullptr && |
| 8167 |
1/2✓ Branch 0 taken 340 times.
✗ Branch 1 not taken.
|
340 | sql_field->zip_dict_name.length != 0) { |
| 8168 |
2/4✓ Branch 0 taken 340 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 340 times.
|
340 | if (compression_dict::acquire_dict_mdl(thd, MDL_SHARED_READ)) { |
| 8169 | ✗ | return true; | |
| 8170 | } | ||
| 8171 | |||
| 8172 | uint64 zip_dict_id = | ||
| 8173 |
1/2✓ Branch 0 taken 340 times.
✗ Branch 1 not taken.
|
340 | compression_dict::get_id_for_name(thd, sql_field->zip_dict_name); |
| 8174 | |||
| 8175 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 340 times.
|
340 | if (zip_dict_id == 0) { |
| 8176 | ✗ | my_error(ER_COMPRESSION_DICTIONARY_DOES_NOT_EXIST, MYF(0), | |
| 8177 | sql_field->zip_dict_name.str); | ||
| 8178 | ✗ | return true; | |
| 8179 | } | ||
| 8180 | 340 | sql_field->zip_dict_id = zip_dict_id; | |
| 8181 | } | ||
| 8182 | |||
| 8183 |
2/2✓ Branch 0 taken 245356 times.
✓ Branch 1 taken 5897439 times.
|
6142795 | if (sql_field->auto_flags & Field::NEXT_NUMBER) auto_increment++; |
| 8184 |
2/2✓ Branch 0 taken 869010 times.
✓ Branch 1 taken 5273785 times.
|
6142795 | switch (sql_field->sql_type) { |
| 8185 | 869010 | case MYSQL_TYPE_GEOMETRY: | |
| 8186 | case MYSQL_TYPE_BLOB: | ||
| 8187 | case MYSQL_TYPE_MEDIUM_BLOB: | ||
| 8188 | case MYSQL_TYPE_TINY_BLOB: | ||
| 8189 | case MYSQL_TYPE_LONG_BLOB: | ||
| 8190 | case MYSQL_TYPE_JSON: | ||
| 8191 | 869010 | blob_columns++; | |
| 8192 | 869010 | break; | |
| 8193 | 5273785 | default: | |
| 8194 |
2/2✓ Branch 0 taken 423 times.
✓ Branch 1 taken 5273362 times.
|
5273785 | if (sql_field->is_array) blob_columns++; |
| 8195 | 5273785 | break; | |
| 8196 | } | ||
| 8197 | } | ||
| 8198 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 749483 times.
|
749483 | if (auto_increment > 1) { |
| 8199 | ✗ | my_error(ER_WRONG_AUTO_KEY, MYF(0)); | |
| 8200 | ✗ | return true; | |
| 8201 | } | ||
| 8202 |
4/6✓ Branch 0 taken 245356 times.
✓ Branch 1 taken 504127 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 245356 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 749483 times.
|
749483 | if (auto_increment && (file->ha_table_flags() & HA_NO_AUTO_INCREMENT)) { |
| 8203 | ✗ | my_error(ER_TABLE_CANT_HANDLE_AUTO_INCREMENT, MYF(0)); | |
| 8204 | ✗ | return true; | |
| 8205 | } | ||
| 8206 |
4/6✓ Branch 0 taken 338464 times.
✓ Branch 1 taken 411019 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 338464 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 749483 times.
|
749483 | if (blob_columns && (file->ha_table_flags() & HA_NO_BLOBS)) { |
| 8207 | ✗ | my_error(ER_TABLE_CANT_HANDLE_BLOB, MYF(0)); | |
| 8208 | ✗ | return true; | |
| 8209 | } | ||
| 8210 | /* | ||
| 8211 | CREATE TABLE[with auto_increment column] SELECT is unsafe as the rows | ||
| 8212 | inserted in the created table depends on the order of the rows fetched | ||
| 8213 | from the select tables. This order may differ on master and slave. We | ||
| 8214 | therefore mark it as unsafe. | ||
| 8215 | */ | ||
| 8216 |
4/4✓ Branch 0 taken 9153 times.
✓ Branch 1 taken 740330 times.
✓ Branch 2 taken 92 times.
✓ Branch 3 taken 9061 times.
|
749483 | if (select_field_count > 0 && auto_increment) |
| 8217 |
1/2✓ Branch 0 taken 92 times.
✗ Branch 1 not taken.
|
92 | thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_CREATE_SELECT_AUTOINC); |
| 8218 | |||
| 8219 | /* | ||
| 8220 | Count keys and key segments. | ||
| 8221 | Also mark redundant keys to be ignored. | ||
| 8222 | */ | ||
| 8223 | uint key_parts; | ||
| 8224 | Mem_root_array<bool> redundant_keys(thd->mem_root, | ||
| 8225 |
1/2✓ Branch 0 taken 749477 times.
✗ Branch 1 not taken.
|
1498961 | alter_info->key_list.size(), false); |
| 8226 |
3/4✓ Branch 0 taken 749476 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 749468 times.
|
749477 | if (count_keys(alter_info->key_list, key_count, &key_parts, fk_key_count, |
| 8227 | &redundant_keys, file->ha_table_flags())) | ||
| 8228 | 8 | return true; | |
| 8229 |
3/4✓ Branch 0 taken 749472 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 749466 times.
|
749468 | if (*key_count > file->max_keys()) { |
| 8230 |
2/4✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
|
6 | my_error(ER_TOO_MANY_KEYS, MYF(0), file->max_keys()); |
| 8231 | 6 | return true; | |
| 8232 | } | ||
| 8233 | |||
| 8234 | /* | ||
| 8235 | Make KEY objects for the keys in the new table. | ||
| 8236 | */ | ||
| 8237 | KEY *key_info; | ||
| 8238 |
1/2✓ Branch 0 taken 749473 times.
✗ Branch 1 not taken.
|
749466 | (*key_info_buffer) = key_info = (KEY *)sql_calloc(sizeof(KEY) * (*key_count)); |
| 8239 | KEY_PART_INFO *key_part_info = | ||
| 8240 |
1/2✓ Branch 0 taken 749473 times.
✗ Branch 1 not taken.
|
749473 | (KEY_PART_INFO *)sql_calloc(sizeof(KEY_PART_INFO) * key_parts); |
| 8241 | |||
| 8242 |
2/4✓ Branch 0 taken 749473 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 749473 times.
|
749473 | if (!*key_info_buffer || !key_part_info) return true; // Out of memory |
| 8243 | |||
| 8244 | 749473 | alter_info->delayed_key_count = 0; | |
| 8245 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 749466 times.
|
749473 | if (alter_info->delayed_key_list.size() > 0) { |
| 8246 | 5 | alter_info->delayed_key_info = | |
| 8247 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | static_cast<KEY *>(sql_calloc(sizeof(KEY) * (*key_count))); |
| 8248 | } | ||
| 8249 | |||
| 8250 |
1/2✓ Branch 0 taken 749465 times.
✗ Branch 1 not taken.
|
1498935 | Mem_root_array<const KEY *> keys_to_check(thd->mem_root); |
| 8251 |
2/4✓ Branch 0 taken 749462 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 749462 times.
|
749465 | if (keys_to_check.reserve(*key_count)) return true; // Out of memory |
| 8252 | |||
| 8253 | 749462 | uint key_number = 0; | |
| 8254 | 749462 | bool primary_key = false; | |
| 8255 | |||
| 8256 | // First prepare non-foreign keys so that they are ready when | ||
| 8257 | // we prepare foreign keys. | ||
| 8258 |
2/2✓ Branch 0 taken 2691136 times.
✓ Branch 1 taken 748090 times.
|
3439226 | for (size_t i = 0; i < alter_info->key_list.size(); i++) { |
| 8259 |
3/4✓ Branch 0 taken 2691136 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 611693 times.
✓ Branch 3 taken 2079443 times.
|
2691136 | if (redundant_keys[i]) continue; // Skip redundant keys |
| 8260 | |||
| 8261 |
1/2✓ Branch 0 taken 2079443 times.
✗ Branch 1 not taken.
|
2079443 | const Key_spec *key = alter_info->key_list[i]; |
| 8262 | |||
| 8263 |
2/2✓ Branch 0 taken 501007 times.
✓ Branch 1 taken 1578436 times.
|
2079443 | if (key->type == KEYTYPE_PRIMARY) { |
| 8264 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 500996 times.
|
501007 | if (primary_key) { |
| 8265 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
11 | my_error(ER_MULTIPLE_PRI_KEY, MYF(0)); |
| 8266 | 11 | return true; | |
| 8267 | } | ||
| 8268 | 500996 | primary_key = true; | |
| 8269 | } | ||
| 8270 | |||
| 8271 |
2/2✓ Branch 0 taken 1466550 times.
✓ Branch 1 taken 612882 times.
|
2079432 | if (key->type != KEYTYPE_FOREIGN) { |
| 8272 |
3/4✓ Branch 0 taken 1466549 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1361 times.
✓ Branch 3 taken 1465188 times.
|
1466550 | if (prepare_key(thd, error_schema_name, error_table_name, create_info, |
| 8273 | &alter_info->create_list, key, key_info_buffer, key_info, | ||
| 8274 | &key_part_info, keys_to_check, key_number, file, | ||
| 8275 | &auto_increment)) | ||
| 8276 | 1361 | return true; | |
| 8277 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 1465182 times.
|
1465191 | for (const auto &it2 : alter_info->delayed_key_list) { |
| 8278 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 3 times.
|
10 | if (it2 == key) { |
| 8279 | 7 | alter_info->delayed_key_info[alter_info->delayed_key_count++] = | |
| 8280 | *key_info; | ||
| 8281 | 7 | break; | |
| 8282 | } | ||
| 8283 | } | ||
| 8284 | 1465189 | key_info++; | |
| 8285 | 1465189 | key_number++; | |
| 8286 | } | ||
| 8287 | } | ||
| 8288 | // If the table is created without PK, we must check if this has | ||
| 8289 | // been disabled and return error. Limit the effect of sql_require_primary_key | ||
| 8290 | // to only those SEs that can participate in replication. | ||
| 8291 |
2/2✓ Branch 0 taken 173833 times.
✓ Branch 1 taken 73588 times.
|
247417 | if (!primary_key && !thd->is_dd_system_thread() && |
| 8292 |
2/2✓ Branch 0 taken 173254 times.
✓ Branch 1 taken 574 times.
|
173833 | !thd->is_initialize_system_thread() && |
| 8293 |
2/2✓ Branch 0 taken 155967 times.
✓ Branch 1 taken 17298 times.
|
173254 | (file->ha_table_flags() & |
| 8294 | 155967 | (HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE)) != 0 && | |
| 8295 |
6/6✓ Branch 0 taken 247417 times.
✓ Branch 1 taken 500673 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 155952 times.
✓ Branch 4 taken 13 times.
✓ Branch 5 taken 748087 times.
|
995532 | thd->variables.sql_require_primary_key && |
| 8296 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 2 times.
|
15 | !(create_info->options & HA_LEX_CREATE_TMP_TABLE)) { |
| 8297 |
1/2✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
|
13 | my_error(ER_TABLE_WITHOUT_PK, MYF(0)); |
| 8298 | 13 | return true; | |
| 8299 | } | ||
| 8300 | |||
| 8301 | /* | ||
| 8302 | At this point all KEY objects are for indexes are fully constructed. | ||
| 8303 | So we can check for duplicate indexes for keys for which it was requested. | ||
| 8304 | */ | ||
| 8305 | const KEY **dup_check_key; | ||
| 8306 | 1677425 | for (dup_check_key = keys_to_check.begin(); | |
| 8307 |
3/4✓ Branch 0 taken 1677421 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 929338 times.
✓ Branch 3 taken 748083 times.
|
1677413 | dup_check_key != keys_to_check.end(); dup_check_key++) { |
| 8308 |
2/4✓ Branch 0 taken 929338 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 929338 times.
|
929338 | if (check_duplicate_key(thd, error_schema_name, error_table_name, |
| 8309 | *dup_check_key, *key_info_buffer, *key_count, | ||
| 8310 | alter_info)) | ||
| 8311 | ✗ | return true; | |
| 8312 | } | ||
| 8313 | |||
| 8314 |
7/8✓ Branch 0 taken 247411 times.
✓ Branch 1 taken 500672 times.
✓ Branch 2 taken 247409 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 247408 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 748080 times.
|
748083 | if (!primary_key && check_promoted_index(file, *key_info_buffer, *key_count)) |
| 8315 | 1 | return true; | |
| 8316 | |||
| 8317 | /* | ||
| 8318 | Any auto increment columns not found during prepare_key? | ||
| 8319 | */ | ||
| 8320 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 748072 times.
|
748080 | if (auto_increment > 0) { |
| 8321 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | my_error(ER_WRONG_AUTO_KEY, MYF(0)); |
| 8322 | 8 | return true; | |
| 8323 | } | ||
| 8324 | |||
| 8325 | /* Sort keys in optimized order */ | ||
| 8326 |
1/2✓ Branch 0 taken 748074 times.
✗ Branch 1 not taken.
|
748072 | std::sort(*key_info_buffer, *key_info_buffer + *key_count, sort_keys()); |
| 8327 | |||
| 8328 | /* | ||
| 8329 | Normal keys are done, now prepare foreign keys. | ||
| 8330 | |||
| 8331 | We do this after sorting normal keys to get predictable behavior | ||
| 8332 | when searching for parent keys for self-referencing foreign keys. | ||
| 8333 | */ | ||
| 8334 | 748074 | bool se_supports_fks = | |
| 8335 | 748074 | (create_info->db_type->flags & HTON_SUPPORTS_FOREIGN_KEYS); | |
| 8336 | |||
| 8337 |
3/4✓ Branch 0 taken 121647 times.
✓ Branch 1 taken 626427 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 121647 times.
|
748074 | assert(se_supports_fks || existing_fks_count == 0); |
| 8338 | |||
| 8339 | 748074 | (*fk_key_count) += existing_fks_count; | |
| 8340 | FOREIGN_KEY *fk_key_info; | ||
| 8341 | 748074 | (*fk_key_info_buffer) = fk_key_info = | |
| 8342 |
1/2✓ Branch 0 taken 748074 times.
✗ Branch 1 not taken.
|
748074 | (FOREIGN_KEY *)sql_calloc(sizeof(FOREIGN_KEY) * (*fk_key_count)); |
| 8343 | |||
| 8344 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 748074 times.
|
748074 | if (!fk_key_info) return true; // Out of memory |
| 8345 | |||
| 8346 | // Copy pre-existing foreign keys. | ||
| 8347 |
2/2✓ Branch 0 taken 220 times.
✓ Branch 1 taken 747854 times.
|
748074 | if (existing_fks_count > 0) |
| 8348 | 220 | memcpy(*fk_key_info_buffer, existing_fks, | |
| 8349 | 220 | existing_fks_count * sizeof(FOREIGN_KEY)); | |
| 8350 | 748074 | uint fk_number = existing_fks_count; | |
| 8351 | 748074 | fk_key_info += existing_fks_count; | |
| 8352 | |||
| 8353 | /* | ||
| 8354 | Check if we are trying to add partitioning to the table with existing | ||
| 8355 | foreign keys and table's storage engine doesn't support foreign keys | ||
| 8356 | over partitioned tables. | ||
| 8357 | */ | ||
| 8358 |
6/6✓ Branch 0 taken 6535 times.
✓ Branch 1 taken 741539 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 6534 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 748073 times.
|
748075 | if (is_partitioned && existing_fks_count > 0 && |
| 8359 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | (!create_info->db_type->partition_flags || |
| 8360 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | create_info->db_type->partition_flags() & HA_CANNOT_PARTITION_FK)) { |
| 8361 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_FOREIGN_KEY_ON_PARTITIONED, MYF(0)); |
| 8362 | 1 | return true; | |
| 8363 | } | ||
| 8364 | |||
| 8365 | /* | ||
| 8366 | Check that definitions of existing foreign keys are not broken by this | ||
| 8367 | ALTER TABLE. Update FOREIGN_KEY::unique_constraint_name if necessary. | ||
| 8368 | */ | ||
| 8369 | 748314 | for (FOREIGN_KEY *fk = *fk_key_info_buffer; | |
| 8370 |
2/2✓ Branch 0 taken 264 times.
✓ Branch 1 taken 748050 times.
|
748314 | fk < (*fk_key_info_buffer) + existing_fks_count; fk++) { |
| 8371 |
3/4✓ Branch 0 taken 264 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✓ Branch 3 taken 241 times.
|
264 | if (prepare_preexisting_foreign_key( |
| 8372 | thd, create_info, alter_info, error_schema_name, error_table_name, | ||
| 8373 | *key_info_buffer, *key_count, existing_fks_table, fk)) | ||
| 8374 | 23 | return true; | |
| 8375 | } | ||
| 8376 | |||
| 8377 | // Prepare new foreign keys. | ||
| 8378 |
2/2✓ Branch 0 taken 2687453 times.
✓ Branch 1 taken 747974 times.
|
3435434 | for (size_t i = 0; i < alter_info->key_list.size(); i++) { |
| 8379 |
3/4✓ Branch 0 taken 2687453 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 611654 times.
✓ Branch 3 taken 2075799 times.
|
2687453 | if (redundant_keys[i]) continue; // Skip redundant keys |
| 8380 | |||
| 8381 |
1/2✓ Branch 0 taken 2075799 times.
✗ Branch 1 not taken.
|
2075799 | Key_spec *key = alter_info->key_list[i]; |
| 8382 | |||
| 8383 |
2/2✓ Branch 0 taken 612874 times.
✓ Branch 1 taken 1462925 times.
|
2075799 | if (key->type == KEYTYPE_FOREIGN) { |
| 8384 |
3/4✓ Branch 0 taken 612874 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 69 times.
✓ Branch 3 taken 612805 times.
|
612874 | if (prepare_foreign_key(thd, create_info, alter_info, error_schema_name, |
| 8385 | error_table_name, is_partitioned, | ||
| 8386 | *key_info_buffer, *key_count, *fk_key_info_buffer, | ||
| 8387 | fk_number, se_supports_fks, find_parent_keys, | ||
| 8388 | down_cast<Foreign_key_spec *>(key), | ||
| 8389 | &fk_max_generated_name_number, fk_key_info)) | ||
| 8390 | 69 | return true; | |
| 8391 | |||
| 8392 |
2/2✓ Branch 0 taken 612771 times.
✓ Branch 1 taken 34 times.
|
612805 | if (se_supports_fks) { |
| 8393 | 612771 | fk_key_info++; | |
| 8394 | 612771 | fk_number++; | |
| 8395 | } | ||
| 8396 | } | ||
| 8397 | } | ||
| 8398 | |||
| 8399 | /* | ||
| 8400 | Check if STRICT SQL mode is active and server is not started with | ||
| 8401 | --explicit-defaults-for-timestamp. Below check was added to prevent implicit | ||
| 8402 | default 0 value of timestamp. When explicit-defaults-for-timestamp server | ||
| 8403 | option is removed, whole set of check can be removed. | ||
| 8404 | |||
| 8405 | Note that this check must be after KEYs have been created as this | ||
| 8406 | can cause the NOT_NULL_FLAG to be set. | ||
| 8407 | */ | ||
| 8408 |
2/2✓ Branch 0 taken 630029 times.
✓ Branch 1 taken 117945 times.
|
747974 | if (thd->variables.sql_mode & MODE_NO_ZERO_DATE && |
| 8409 |
2/2✓ Branch 0 taken 134 times.
✓ Branch 1 taken 629895 times.
|
630029 | !thd->variables.explicit_defaults_for_timestamp) { |
| 8410 | 134 | it.rewind(); | |
| 8411 |
2/2✓ Branch 0 taken 286 times.
✓ Branch 1 taken 134 times.
|
420 | while ((sql_field = it++)) { |
| 8412 |
3/4✓ Branch 0 taken 271 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 34 times.
✓ Branch 3 taken 237 times.
|
542 | if (!sql_field->constant_default && !sql_field->gcol_info && |
| 8413 | 271 | is_timestamp_type(sql_field->sql_type) && | |
| 8414 |
5/6✓ Branch 0 taken 271 times.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 22 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 286 times.
|
569 | (sql_field->flags & NOT_NULL_FLAG) && |
| 8415 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | !(sql_field->auto_flags & Field::DEFAULT_NOW)) { |
| 8416 | /* | ||
| 8417 | An error should be reported if: | ||
| 8418 | - there is no explicit DEFAULT clause (default column value); | ||
| 8419 | - this is a TIMESTAMP column; | ||
| 8420 | - the column is not NULL; | ||
| 8421 | - this is not the DEFAULT CURRENT_TIMESTAMP column. | ||
| 8422 | And from checks before while loop, | ||
| 8423 | - STRICT SQL mode is active; | ||
| 8424 | - server is not started with --explicit-defaults-for-timestamp | ||
| 8425 | |||
| 8426 | In other words, an error should be reported if | ||
| 8427 | - STRICT SQL mode is active; | ||
| 8428 | - the column definition is equivalent to | ||
| 8429 | 'column_name TIMESTAMP DEFAULT 0'. | ||
| 8430 | */ | ||
| 8431 | |||
| 8432 | ✗ | my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name); | |
| 8433 | ✗ | return true; | |
| 8434 | } | ||
| 8435 | } | ||
| 8436 | } | ||
| 8437 | |||
| 8438 | /* If fixed row records, we need one bit to check for deleted rows */ | ||
| 8439 |
2/2✓ Branch 0 taken 138676 times.
✓ Branch 1 taken 609298 times.
|
747974 | if (!(create_info->table_options & HA_OPTION_PACK_RECORD)) |
| 8440 | 138676 | create_info->null_bits++; | |
| 8441 | 747974 | ulong data_offset = (create_info->null_bits + 7) / 8; | |
| 8442 | 747974 | size_t reclength = data_offset; | |
| 8443 | 747974 | it.rewind(); | |
| 8444 |
2/2✓ Branch 0 taken 6138618 times.
✓ Branch 1 taken 747981 times.
|
6886597 | while ((sql_field = it++)) { |
| 8445 |
1/2✓ Branch 0 taken 6138618 times.
✗ Branch 1 not taken.
|
6138618 | size_t length = sql_field->pack_length(); |
| 8446 |
2/2✓ Branch 0 taken 6136383 times.
✓ Branch 1 taken 2235 times.
|
6138618 | if (sql_field->offset + data_offset + length > reclength) |
| 8447 | 6136383 | reclength = sql_field->offset + data_offset + length; | |
| 8448 | } | ||
| 8449 |
3/4✓ Branch 0 taken 747977 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 747970 times.
|
747981 | if (reclength > file->max_record_length()) { |
| 8450 | 7 | my_error(ER_TOO_BIG_ROWSIZE, MYF(0), | |
| 8451 |
2/4✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
|
7 | static_cast<long>(file->max_record_length())); |
| 8452 | 7 | return true; | |
| 8453 | } | ||
| 8454 | |||
| 8455 | 747970 | return false; | |
| 8456 | 756932 | } | |
| 8457 | |||
| 8458 | /** | ||
| 8459 | @brief check comment length of table, column, index and partition | ||
| 8460 | |||
| 8461 | @details If comment length is more than the standard length | ||
| 8462 | truncate it and store the comment length up to the standard | ||
| 8463 | comment length size | ||
| 8464 | |||
| 8465 | @param thd Thread handle | ||
| 8466 | @param comment_str Comment string | ||
| 8467 | @param[in,out] comment_len Comment length | ||
| 8468 | @param max_len Maximum allowed comment length | ||
| 8469 | @param err_code Error message | ||
| 8470 | @param comment_name Type of comment | ||
| 8471 | |||
| 8472 | @return Operation status | ||
| 8473 | @retval true Error found | ||
| 8474 | @retval false On success | ||
| 8475 | */ | ||
| 8476 | |||
| 8477 | 8609005 | bool validate_comment_length(THD *thd, const char *comment_str, | |
| 8478 | size_t *comment_len, uint max_len, uint err_code, | ||
| 8479 | const char *comment_name) { | ||
| 8480 | 8609005 | size_t length = 0; | |
| 8481 |
1/2✓ Branch 0 taken 8609025 times.
✗ Branch 1 not taken.
|
8609005 | DBUG_TRACE; |
| 8482 | |||
| 8483 |
2/2✓ Branch 0 taken 2167065 times.
✓ Branch 1 taken 6441960 times.
|
8609025 | if (comment_str == nullptr) { |
| 8484 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2167065 times.
|
2167065 | assert(*comment_len == 0); |
| 8485 | 2167065 | return false; | |
| 8486 | } | ||
| 8487 | 12883923 | size_t tmp_len = system_charset_info->cset->charpos( | |
| 8488 |
1/2✓ Branch 0 taken 6441963 times.
✗ Branch 1 not taken.
|
6441960 | system_charset_info, comment_str, comment_str + *comment_len, max_len); |
| 8489 |
2/2✓ Branch 0 taken 41 times.
✓ Branch 1 taken 6441922 times.
|
6441963 | if (tmp_len < *comment_len) { |
| 8490 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 23 times.
|
41 | if (thd->is_strict_mode()) { |
| 8491 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | my_error(err_code, MYF(0), comment_name, static_cast<ulong>(max_len)); |
| 8492 | 18 | return true; | |
| 8493 | } | ||
| 8494 | char warn_buff[MYSQL_ERRMSG_SIZE]; | ||
| 8495 | 23 | length = | |
| 8496 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | snprintf(warn_buff, sizeof(warn_buff), ER_THD_NONCONST(thd, err_code), |
| 8497 | comment_name, static_cast<ulong>(max_len)); | ||
| 8498 | /* do not push duplicate warnings */ | ||
| 8499 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | if (!thd->get_stmt_da()->has_sql_condition(warn_buff, length)) |
| 8500 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | push_warning(thd, Sql_condition::SL_WARNING, err_code, warn_buff); |
| 8501 | 23 | *comment_len = tmp_len; | |
| 8502 | } | ||
| 8503 | 6441945 | return false; | |
| 8504 | 8609028 | } | |
| 8505 | |||
| 8506 | /* | ||
| 8507 | Set table default charset, if not set | ||
| 8508 | |||
| 8509 | SYNOPSIS | ||
| 8510 | set_table_default_charset() | ||
| 8511 | create_info Table create information | ||
| 8512 | |||
| 8513 | DESCRIPTION | ||
| 8514 | If the table character set was not given explicitly, | ||
| 8515 | let's fetch the database default character set and | ||
| 8516 | apply it to the table. | ||
| 8517 | */ | ||
| 8518 | |||
| 8519 | 847602 | static bool set_table_default_charset(THD *thd, HA_CREATE_INFO *create_info, | |
| 8520 | const dd::Schema &schema) { | ||
| 8521 | /* | ||
| 8522 | If the table character set was not given explicitly, | ||
| 8523 | let's fetch the database default character set and | ||
| 8524 | apply it to the table. | ||
| 8525 | */ | ||
| 8526 |
2/2✓ Branch 0 taken 236212 times.
✓ Branch 1 taken 611390 times.
|
847602 | if (create_info->default_table_charset == nullptr) { |
| 8527 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 236214 times.
|
236212 | if (get_default_db_collation(schema, &create_info->default_table_charset)) |
| 8528 | ✗ | return true; | |
| 8529 | } else { | ||
| 8530 |
3/6✓ Branch 0 taken 3904 times.
✓ Branch 1 taken 607486 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3904 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
611390 | assert((create_info->used_fields & HA_CREATE_USED_CHARSET) == 0 || |
| 8531 | (create_info->used_fields & HA_CREATE_USED_DEFAULT_CHARSET) || | ||
| 8532 | create_info->default_table_charset == create_info->table_charset); | ||
| 8533 | |||
| 8534 |
2/2✓ Branch 0 taken 438733 times.
✓ Branch 1 taken 172657 times.
|
611390 | if ((create_info->used_fields & HA_CREATE_USED_DEFAULT_CHARSET) && |
| 8535 |
2/2✓ Branch 0 taken 18480 times.
✓ Branch 1 taken 420253 times.
|
438733 | !(create_info->used_fields & HA_CREATE_USED_DEFAULT_COLLATE) && |
| 8536 |
2/2✓ Branch 0 taken 3523 times.
✓ Branch 1 taken 14957 times.
|
18480 | create_info->default_table_charset == &my_charset_utf8mb4_0900_ai_ci) { |
| 8537 | 3523 | create_info->default_table_charset = | |
| 8538 | 3523 | thd->variables.default_collation_for_utf8mb4; | |
| 8539 | |||
| 8540 | // ALTER TABLE ... CONVERT TO CHARACTER SET ... | ||
| 8541 |
2/2✓ Branch 0 taken 328 times.
✓ Branch 1 taken 3195 times.
|
3523 | if (create_info->used_fields & HA_CREATE_USED_CHARSET) { |
| 8542 | 328 | create_info->table_charset = create_info->default_table_charset; | |
| 8543 | } | ||
| 8544 | } | ||
| 8545 | } | ||
| 8546 | |||
| 8547 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 847604 times.
|
847604 | if (create_info->default_table_charset == nullptr) |
| 8548 | ✗ | create_info->default_table_charset = thd->collation(); | |
| 8549 | |||
| 8550 | 847604 | return false; | |
| 8551 | } | ||
| 8552 | |||
| 8553 | /* | ||
| 8554 | Extend long VARCHAR fields to blob & prepare field if it's a blob | ||
| 8555 | |||
| 8556 | SYNOPSIS | ||
| 8557 | prepare_blob_field() | ||
| 8558 | sql_field Field to check | ||
| 8559 | |||
| 8560 | RETURN | ||
| 8561 | 0 ok | ||
| 8562 | 1 Error (sql_field can't be converted to blob) | ||
| 8563 | In this case the error is given | ||
| 8564 | */ | ||
| 8565 | |||
| 8566 | 6757305 | static bool prepare_blob_field(THD *thd, Create_field *sql_field, | |
| 8567 | bool convert_character_set) { | ||
| 8568 |
1/2✓ Branch 0 taken 6757318 times.
✗ Branch 1 not taken.
|
6757305 | DBUG_TRACE; |
| 8569 | |||
| 8570 | // Skip typed array fields | ||
| 8571 |
2/2✓ Branch 0 taken 423 times.
✓ Branch 1 taken 6756895 times.
|
6757318 | if (sql_field->is_array) return false; |
| 8572 | |||
| 8573 |
5/6✓ Branch 0 taken 6756884 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 705993 times.
✓ Branch 3 taken 6050891 times.
✓ Branch 4 taken 25 times.
✓ Branch 5 taken 6756859 times.
|
7462888 | if (sql_field->max_display_width_in_bytes() > MAX_FIELD_VARCHARLENGTH && |
| 8574 |
2/2✓ Branch 0 taken 25 times.
✓ Branch 1 taken 705968 times.
|
705993 | !(sql_field->flags & BLOB_FLAG)) { |
| 8575 | /* Convert long VARCHAR columns to TEXT or BLOB */ | ||
| 8576 | char warn_buff[MYSQL_ERRMSG_SIZE]; | ||
| 8577 | |||
| 8578 |
5/6✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 16 times.
✓ Branch 4 taken 9 times.
✓ Branch 5 taken 16 times.
|
25 | if (sql_field->constant_default || thd->is_strict_mode()) { |
| 8579 | 9 | my_error(ER_TOO_BIG_FIELDLENGTH, MYF(0), sql_field->field_name, | |
| 8580 | 9 | static_cast<ulong>(MAX_FIELD_VARCHARLENGTH / | |
| 8581 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
9 | sql_field->charset->mbmaxlen)); |
| 8582 | 9 | return true; | |
| 8583 | } | ||
| 8584 | 16 | sql_field->sql_type = | |
| 8585 |
2/4✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
|
16 | get_blob_type_from_length(sql_field->max_display_width_in_bytes()); |
| 8586 | 16 | sql_field->flags |= BLOB_FLAG; | |
| 8587 |
1/2✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
|
32 | snprintf(warn_buff, sizeof(warn_buff), ER_THD(thd, ER_AUTO_CONVERT), |
| 8588 | sql_field->field_name, | ||
| 8589 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 12 times.
|
16 | (sql_field->charset == &my_charset_bin) ? "VARBINARY" : "VARCHAR", |
| 8590 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 12 times.
|
16 | (sql_field->charset == &my_charset_bin) ? "BLOB" : "TEXT"); |
| 8591 |
1/2✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
|
16 | push_warning(thd, Sql_condition::SL_NOTE, ER_AUTO_CONVERT, warn_buff); |
| 8592 | } | ||
| 8593 | |||
| 8594 | /* | ||
| 8595 | If the user has given a length to the BLOB/TEXT column explicitly, we make | ||
| 8596 | sure that we choose the most appropriate data type. For instance, "TEXT(63) | ||
| 8597 | CHARACTER SET utf8mb4" is automatically converted to TINYTEXT since TINYTEXT | ||
| 8598 | can hold 255 _bytes_ of data (which is enough for 63 _characters_ of | ||
| 8599 | utf8mb4). | ||
| 8600 | |||
| 8601 | Also, if we are changing the character set to a character set that requires | ||
| 8602 | more storage per character, we might need to change the column to a bigger | ||
| 8603 | type in order to not loose any data. Consider the following example: | ||
| 8604 | |||
| 8605 | CREATE TABLE t1 (a TINYTEXT CHARACTER SET latin1); | ||
| 8606 | ALTER TABLE t1 CONVERT TO CHARACTER SET utf8mb4; | ||
| 8607 | |||
| 8608 | TINYTEXT can store up to 255 _bytes_ of data, and since "latin1" requires | ||
| 8609 | one byte per character the user can store 255 _characters_ into this column. | ||
| 8610 | If we are changing the character set to utf8mb4, each character suddenly | ||
| 8611 | requires 4 bytes of storage. So an existing string in the column "a" that | ||
| 8612 | is 255 characters long now suddenly requires 1020 _bytes_ of storage. This | ||
| 8613 | does not fit into TINYTEXT, so we need to switch the data type to TEXT in | ||
| 8614 | order not to loose any existing data (TEXT can store up to 65536 _bytes_ of | ||
| 8615 | data, which is 16384 _characters_ of utf8mb4 data). | ||
| 8616 | */ | ||
| 8617 |
2/2✓ Branch 0 taken 1001028 times.
✓ Branch 1 taken 5755847 times.
|
6756875 | if ((sql_field->flags & BLOB_FLAG) && |
| 8618 |
2/2✓ Branch 0 taken 709860 times.
✓ Branch 1 taken 291168 times.
|
1001028 | (sql_field->sql_type == FIELD_TYPE_BLOB || |
| 8619 |
2/2✓ Branch 0 taken 705936 times.
✓ Branch 1 taken 3924 times.
|
709860 | sql_field->sql_type == FIELD_TYPE_TINY_BLOB || |
| 8620 |
2/2✓ Branch 0 taken 367378 times.
✓ Branch 1 taken 338558 times.
|
705936 | sql_field->sql_type == FIELD_TYPE_MEDIUM_BLOB)) { |
| 8621 |
2/2✓ Branch 0 taken 1306 times.
✓ Branch 1 taken 661161 times.
|
662470 | if (sql_field->explicit_display_width()) { |
| 8622 | 1306 | sql_field->sql_type = | |
| 8623 |
2/4✓ Branch 0 taken 1306 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1306 times.
✗ Branch 3 not taken.
|
1306 | get_blob_type_from_length(sql_field->max_display_width_in_bytes()); |
| 8624 |
3/4✓ Branch 0 taken 1269 times.
✓ Branch 1 taken 659892 times.
✓ Branch 2 taken 1269 times.
✗ Branch 3 not taken.
|
661161 | } else if (convert_character_set && sql_field->field != nullptr) { |
| 8625 | // If sql_field->field == nullptr, it means that we are doing a "CONVERT | ||
| 8626 | // TO CHARACTER SET" _and_ adding a new column in the same statement. | ||
| 8627 | // The new column will have the new correct character set, so we don't | ||
| 8628 | // need to do anything for that column here. | ||
| 8629 | const size_t max_codepoints_old_field = | ||
| 8630 |
1/2✓ Branch 0 taken 1269 times.
✗ Branch 1 not taken.
|
1269 | sql_field->field->char_length() / |
| 8631 |
1/2✓ Branch 0 taken 1269 times.
✗ Branch 1 not taken.
|
1269 | sql_field->field->charset()->mbmaxlen; |
| 8632 | 1269 | const size_t max_bytes_new_field = | |
| 8633 | 1269 | max_codepoints_old_field * sql_field->charset->mbmaxlen; | |
| 8634 |
1/2✓ Branch 0 taken 1269 times.
✗ Branch 1 not taken.
|
1269 | sql_field->sql_type = get_blob_type_from_length(max_bytes_new_field); |
| 8635 | } | ||
| 8636 | } | ||
| 8637 | |||
| 8638 | 6756872 | return false; | |
| 8639 | 6757304 | } | |
| 8640 | |||
| 8641 | /** | ||
| 8642 | Struct for representing the result of checking if a table exists | ||
| 8643 | before trying to create it. The result has two different | ||
| 8644 | dimensions; if the table actually exists, and if an error | ||
| 8645 | occurred. If the table exists m_error will still be false if this is | ||
| 8646 | CREATE IF NOT EXISTS. | ||
| 8647 | */ | ||
| 8648 | struct Table_exists_result { | ||
| 8649 | /** true if the table already exists */ | ||
| 8650 | bool m_table_exists; | ||
| 8651 | |||
| 8652 | /** true if my_error() has been called and an error must be propagated. */ | ||
| 8653 | bool m_error; | ||
| 8654 | }; | ||
| 8655 | |||
| 8656 | /** | ||
| 8657 | Check if table already exists. | ||
| 8658 | |||
| 8659 | @param thd thread handle | ||
| 8660 | @param schema_name schema name. | ||
| 8661 | @param table_name table name. | ||
| 8662 | @param alias alt representation of table_name. | ||
| 8663 | @param ha_lex_create_tmp_table true if creating a tmp table. | ||
| 8664 | @param ha_create_if_not_exists true if this is CREATE IF NOT EXISTS. | ||
| 8665 | @param internal_tmp_table true if this is an internal tmp table. | ||
| 8666 | |||
| 8667 | @return false if successful, true otherwise. | ||
| 8668 | */ | ||
| 8669 | 758795 | static Table_exists_result check_if_table_exists( | |
| 8670 | THD *thd, const char *schema_name, const char *table_name, | ||
| 8671 | const char *alias, bool ha_lex_create_tmp_table, | ||
| 8672 | bool ha_create_if_not_exists, bool internal_tmp_table) { | ||
| 8673 |
4/4✓ Branch 0 taken 52543 times.
✓ Branch 1 taken 706252 times.
✓ Branch 2 taken 71 times.
✓ Branch 3 taken 758724 times.
|
811338 | if (ha_lex_create_tmp_table && |
| 8674 |
2/2✓ Branch 0 taken 71 times.
✓ Branch 1 taken 52472 times.
|
52543 | find_temporary_table(thd, schema_name, table_name)) { |
| 8675 |
2/2✓ Branch 0 taken 55 times.
✓ Branch 1 taken 16 times.
|
71 | if (ha_create_if_not_exists) { |
| 8676 | 55 | push_warning_printf(thd, Sql_condition::SL_NOTE, ER_TABLE_EXISTS_ERROR, | |
| 8677 | ER_THD(thd, ER_TABLE_EXISTS_ERROR), alias); | ||
| 8678 | 55 | return {true, false}; | |
| 8679 | } | ||
| 8680 | 16 | my_error(ER_TABLE_EXISTS_ERROR, MYF(0), alias); | |
| 8681 | 16 | return {true, true}; | |
| 8682 | } | ||
| 8683 | |||
| 8684 |
4/4✓ Branch 0 taken 670826 times.
✓ Branch 1 taken 87898 times.
✓ Branch 2 taken 619515 times.
✓ Branch 3 taken 51311 times.
|
1378249 | if (!internal_tmp_table && !ha_lex_create_tmp_table && |
| 8685 |
12/20✓ Branch 0 taken 619518 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 619524 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 619525 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 619525 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 213180 times.
✓ Branch 9 taken 406345 times.
✓ Branch 10 taken 619523 times.
✓ Branch 11 taken 139211 times.
✓ Branch 12 taken 619524 times.
✓ Branch 13 taken 139211 times.
✓ Branch 14 taken 213179 times.
✓ Branch 15 taken 545560 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
|
1378249 | !dd::get_dictionary()->is_dd_table_name(schema_name, table_name)) { |
| 8686 | 213179 | const dd::Abstract_table *at = nullptr; | |
| 8687 |
4/8✓ Branch 0 taken 213181 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 213181 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 213175 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 213178 times.
|
213179 | if (thd->dd_client()->acquire(schema_name, table_name, &at)) { |
| 8688 | 6357 | return {false, true}; | |
| 8689 | } | ||
| 8690 | |||
| 8691 |
2/2✓ Branch 0 taken 6357 times.
✓ Branch 1 taken 206821 times.
|
213178 | if (at != nullptr) { |
| 8692 |
2/2✓ Branch 0 taken 5269 times.
✓ Branch 1 taken 1088 times.
|
6357 | if (ha_create_if_not_exists) { |
| 8693 |
2/4✓ Branch 0 taken 5269 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5269 times.
✗ Branch 3 not taken.
|
5269 | push_warning_printf(thd, Sql_condition::SL_NOTE, ER_TABLE_EXISTS_ERROR, |
| 8694 | ER_THD(thd, ER_TABLE_EXISTS_ERROR), alias); | ||
| 8695 | 5269 | return {true, false}; | |
| 8696 | } | ||
| 8697 |
1/2✓ Branch 0 taken 1088 times.
✗ Branch 1 not taken.
|
1088 | my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name); |
| 8698 | 1088 | return {true, true}; | |
| 8699 | } | ||
| 8700 | } | ||
| 8701 | |||
| 8702 | /* | ||
| 8703 | Check that table with given name does not already | ||
| 8704 | exist in any storage engine. In such a case it should | ||
| 8705 | be discovered and the error ER_TABLE_EXISTS_ERROR be returned | ||
| 8706 | unless user specified CREATE TABLE IF EXISTS | ||
| 8707 | An exclusive metadata lock ensures that no | ||
| 8708 | one else is attempting to discover the table. Since | ||
| 8709 | it's not on disk as a frm file, no one could be using it! | ||
| 8710 | */ | ||
| 8711 |
2/2✓ Branch 0 taken 699908 times.
✓ Branch 1 taken 52473 times.
|
1452290 | if (!ha_lex_create_tmp_table && |
| 8712 |
12/20✓ Branch 0 taken 699908 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 699910 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 699911 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 699909 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 293565 times.
✓ Branch 9 taken 406344 times.
✓ Branch 10 taken 699910 times.
✓ Branch 11 taken 52472 times.
✓ Branch 12 taken 699912 times.
✓ Branch 13 taken 52472 times.
✓ Branch 14 taken 293567 times.
✓ Branch 15 taken 458817 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
|
1452290 | !dd::get_dictionary()->is_dd_table_name(schema_name, table_name)) { |
| 8713 | 293567 | int retcode = ha_table_exists_in_engine(thd, schema_name, table_name); | |
| 8714 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 293544 times.
|
293567 | DBUG_PRINT("info", ("exists_in_engine: %u", retcode)); |
| 8715 |
1/3✓ Branch 0 taken 293567 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
|
293567 | switch (retcode) { |
| 8716 | 293567 | case HA_ERR_NO_SUCH_TABLE: | |
| 8717 | /* Normal case, no table exists. we can go and create it */ | ||
| 8718 | 293567 | break; | |
| 8719 | |||
| 8720 | ✗ | case HA_ERR_TABLE_EXIST: | |
| 8721 | ✗ | DBUG_PRINT("info", ("Table existed in handler")); | |
| 8722 | |||
| 8723 | ✗ | if (ha_create_if_not_exists) { | |
| 8724 | ✗ | push_warning_printf(thd, Sql_condition::SL_NOTE, | |
| 8725 | ER_TABLE_EXISTS_ERROR, | ||
| 8726 | ER_THD(thd, ER_TABLE_EXISTS_ERROR), alias); | ||
| 8727 | ✗ | return {true, false}; | |
| 8728 | } | ||
| 8729 | ✗ | my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name); | |
| 8730 | ✗ | return {true, true}; | |
| 8731 | break; | ||
| 8732 | |||
| 8733 | ✗ | default: | |
| 8734 | ✗ | DBUG_PRINT("info", ("error: %u from storage engine", retcode)); | |
| 8735 | ✗ | my_error(retcode, MYF(0), table_name); | |
| 8736 | ✗ | return {true, true}; | |
| 8737 | } | ||
| 8738 | } | ||
| 8739 | 752384 | return {false, false}; | |
| 8740 | } | ||
| 8741 | |||
| 8742 | /** | ||
| 8743 | Create a table | ||
| 8744 | |||
| 8745 | @param thd Thread object | ||
| 8746 | @param schema DD schema object | ||
| 8747 | @param db Database | ||
| 8748 | @param table_name Table name | ||
| 8749 | @param error_table_name The real table name in case table_name is a | ||
| 8750 | temporary table (ALTER). Used for error messages and for checking whether the | ||
| 8751 | table is a white listed system table. | ||
| 8752 | @param path Path to table (i.e. to its .FRM file without | ||
| 8753 | the extension). | ||
| 8754 | @param create_info Create information (like MAX_ROWS) | ||
| 8755 | @param alter_info Description of fields and keys for new table | ||
| 8756 | @param internal_tmp_table Set to true if this is an internal temporary table | ||
| 8757 | (From ALTER TABLE) | ||
| 8758 | @param select_field_count Number of fields coming from SELECT part of | ||
| 8759 | CREATE TABLE ... SELECT statement. Must be zero | ||
| 8760 | for standard create of table. | ||
| 8761 | @param find_parent_keys Indicates whether we need to lookup name of unique | ||
| 8762 | constraint in parent table for foreign keys. | ||
| 8763 | @param no_ha_table Indicates that only .FRM file (and PAR file if | ||
| 8764 | table is partitioned) needs to be created and not a table in the storage | ||
| 8765 | engine. | ||
| 8766 | @param do_not_store_in_dd Indicates that we should postpone storing table | ||
| 8767 | object in the data-dictionary. Requires SE | ||
| 8768 | supporting atomic DDL and no_ha_table flag set. | ||
| 8769 | @param[out] is_trans Identifies the type of engine where the table | ||
| 8770 | was created: either trans or non-trans. | ||
| 8771 | @param[out] key_info Array of KEY objects describing keys in table | ||
| 8772 | which was created. | ||
| 8773 | @param[out] key_count Number of keys in table which was created. | ||
| 8774 | @param keys_onoff Enable or disable keys. | ||
| 8775 | @param[out] fk_key_info Array of FOREIGN_KEY objects describing foreign | ||
| 8776 | keys in table which was created. | ||
| 8777 | @param[out] fk_key_count Number of foreign keys in table which was created. | ||
| 8778 | @param[in] existing_fk_info Array of FOREIGN_KEY objects for foreign keys | ||
| 8779 | which already existed in the table | ||
| 8780 | (in case of ALTER TABLE). | ||
| 8781 | @param[in] existing_fk_count Number of pre-existing foreign keys. | ||
| 8782 | @param[in] existing_fk_table dd::Table object for table version from which | ||
| 8783 | pre-existing foreign keys come from. Needed | ||
| 8784 | for error reporting. | ||
| 8785 | @param[in] fk_max_generated_name_number Max value of number component among | ||
| 8786 | existing generated foreign key names. | ||
| 8787 | @param[out] table_def Data-dictionary object describing the table | ||
| 8788 | created if do_not_store_in_dd option was | ||
| 8789 | used or because the table is temporary and | ||
| 8790 | was not open due to no_ha_table. Not set | ||
| 8791 | otherwise. | ||
| 8792 | @param[out] post_ddl_ht Set to handlerton for table's SE, if this SE | ||
| 8793 | supports atomic DDL, so caller can call SE | ||
| 8794 | post DDL hook after committing transaction. | ||
| 8795 | |||
| 8796 | If one creates a temporary table, this is automatically opened | ||
| 8797 | |||
| 8798 | Note that this function assumes that caller already have taken | ||
| 8799 | exclusive metadata lock on table being created or used some other | ||
| 8800 | way to ensure that concurrent operations won't intervene. | ||
| 8801 | mysql_create_table() is a wrapper that can be used for this. | ||
| 8802 | |||
| 8803 | @note On failure, for engines supporting atomic DDL, the caller must | ||
| 8804 | rollback statement and transaction before doing anything else. | ||
| 8805 | |||
| 8806 | @retval false OK | ||
| 8807 | @retval true error | ||
| 8808 | */ | ||
| 8809 | |||
| 8810 | 759419 | static bool create_table_impl( | |
| 8811 | THD *thd, const dd::Schema &schema, const char *db, const char *table_name, | ||
| 8812 | const char *error_table_name, const char *path, HA_CREATE_INFO *create_info, | ||
| 8813 | Alter_info *alter_info, bool internal_tmp_table, uint select_field_count, | ||
| 8814 | bool find_parent_keys, bool no_ha_table, bool do_not_store_in_dd, | ||
| 8815 | bool *is_trans, KEY **key_info, uint *key_count, | ||
| 8816 | Alter_info::enum_enable_or_disable keys_onoff, FOREIGN_KEY **fk_key_info, | ||
| 8817 | uint *fk_key_count, FOREIGN_KEY *existing_fk_info, uint existing_fk_count, | ||
| 8818 | const dd::Table *existing_fk_table, uint fk_max_generated_name_number, | ||
| 8819 | std::unique_ptr<dd::Table> *table_def, handlerton **post_ddl_ht) { | ||
| 8820 |
1/2✓ Branch 0 taken 759433 times.
✗ Branch 1 not taken.
|
759419 | DBUG_TRACE; |
| 8821 |
5/8✓ Branch 0 taken 759431 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 759434 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 21 times.
✓ Branch 5 taken 759413 times.
✓ Branch 6 taken 21 times.
✗ Branch 7 not taken.
|
759433 | DBUG_PRINT("enter", ("db: '%s' table: '%s' tmp: %d", db, table_name, |
| 8822 | internal_tmp_table)); | ||
| 8823 | |||
| 8824 | // Check that we have at least one visible column. | ||
| 8825 | 759434 | bool has_visible_column = false; | |
| 8826 |
5/8✓ Branch 0 taken 759435 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 759433 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 759687 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 759680 times.
✓ Branch 7 taken 7 times.
|
759688 | for (const Create_field &create_field : alter_info->create_list) { |
| 8827 |
2/2✓ Branch 0 taken 759426 times.
✓ Branch 1 taken 254 times.
|
759680 | if (create_field.hidden == dd::Column::enum_hidden_type::HT_VISIBLE) { |
| 8828 | 759426 | has_visible_column = true; | |
| 8829 | 759426 | break; | |
| 8830 | } | ||
| 8831 | } | ||
| 8832 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 759427 times.
|
759433 | if (!has_visible_column) { |
| 8833 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | my_error(ER_TABLE_MUST_HAVE_A_VISIBLE_COLUMN, MYF(0)); |
| 8834 | 6 | return true; | |
| 8835 | } | ||
| 8836 | |||
| 8837 |
3/4✓ Branch 0 taken 759426 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 52 times.
✓ Branch 3 taken 759374 times.
|
759427 | if (check_engine(thd, db, table_name, create_info, alter_info)) return true; |
| 8838 | |||
| 8839 | // Secondary engine cannot be defined for temporary tables. | ||
| 8840 |
2/2✓ Branch 0 taken 119 times.
✓ Branch 1 taken 759255 times.
|
759374 | if (create_info->secondary_engine.str != nullptr && |
| 8841 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 117 times.
|
119 | create_info->options & HA_LEX_CREATE_TMP_TABLE) { |
| 8842 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | my_error(ER_SECONDARY_ENGINE, MYF(0), "Temporary tables not supported"); |
| 8843 | 2 | return true; | |
| 8844 | } | ||
| 8845 | |||
| 8846 |
2/4✓ Branch 0 taken 759359 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 759359 times.
|
759372 | if (set_table_default_charset(thd, create_info, schema)) return true; |
| 8847 | |||
| 8848 |
1/2✓ Branch 0 taken 759366 times.
✗ Branch 1 not taken.
|
759359 | const char *alias = table_case_name(create_info, table_name); |
| 8849 | |||
| 8850 | 759366 | partition_info *part_info = thd->work_part_info; | |
| 8851 | |||
| 8852 | std::unique_ptr<handler, Destroy_only<handler>> file(get_new_handler( | ||
| 8853 | (TABLE_SHARE *)nullptr, | ||
| 8854 | 759369 | (part_info || | |
| 8855 |
2/2✓ Branch 0 taken 638117 times.
✓ Branch 1 taken 114241 times.
|
752358 | (create_info->db_type->partition_flags && |
| 8856 |
3/4✓ Branch 0 taken 638120 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 638116 times.
|
638117 | (create_info->db_type->partition_flags() & HA_USE_AUTO_PARTITION))), |
| 8857 |
3/4✓ Branch 0 taken 752358 times.
✓ Branch 1 taken 7008 times.
✓ Branch 2 taken 759372 times.
✗ Branch 3 not taken.
|
1518735 | thd->mem_root, create_info->db_type)); |
| 8858 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 759373 times.
|
759376 | if (file.get() == nullptr) { |
| 8859 | ✗ | mem_alloc_error(sizeof(handler)); | |
| 8860 | ✗ | return true; | |
| 8861 | } | ||
| 8862 | |||
| 8863 |
5/6✓ Branch 0 taken 752359 times.
✓ Branch 1 taken 7014 times.
✓ Branch 2 taken 638121 times.
✓ Branch 3 taken 114238 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 759373 times.
|
1397494 | if (!part_info && create_info->db_type->partition_flags && |
| 8864 |
2/4✓ Branch 0 taken 638121 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 638121 times.
|
638121 | (create_info->db_type->partition_flags() & HA_USE_AUTO_PARTITION)) { |
| 8865 | ✗ | Partition_handler *part_handler = file->get_partition_handler(); | |
| 8866 | ✗ | assert(part_handler != nullptr); | |
| 8867 | |||
| 8868 | /* | ||
| 8869 | Table is not defined as a partitioned table but the engine handles | ||
| 8870 | all tables as partitioned. The handler will set up the partition info | ||
| 8871 | object with the default settings. | ||
| 8872 | */ | ||
| 8873 | ✗ | thd->work_part_info = part_info = new (thd->mem_root) partition_info(); | |
| 8874 | ✗ | if (!part_info) { | |
| 8875 | ✗ | mem_alloc_error(sizeof(partition_info)); | |
| 8876 | ✗ | return true; | |
| 8877 | } | ||
| 8878 | ✗ | part_handler->set_auto_partitions(part_info); | |
| 8879 | ✗ | part_info->default_engine_type = create_info->db_type; | |
| 8880 | ✗ | part_info->is_auto_partitioned = true; | |
| 8881 | } | ||
| 8882 |
2/2✓ Branch 0 taken 7012 times.
✓ Branch 1 taken 752361 times.
|
759373 | if (part_info) { |
| 8883 | /* | ||
| 8884 | The table has been specified as a partitioned table. | ||
| 8885 | If this is part of an ALTER TABLE the handler will be the partition | ||
| 8886 | handler but we need to specify the default handler to use for | ||
| 8887 | partitions also in the call to check_partition_info. We transport | ||
| 8888 | this information in the default_db_type variable, it is either | ||
| 8889 | DB_TYPE_DEFAULT or the engine set in the ALTER TABLE command. | ||
| 8890 | */ | ||
| 8891 | handlerton *engine_type; | ||
| 8892 |
1/2✓ Branch 0 taken 7012 times.
✗ Branch 1 not taken.
|
7012 | List_iterator<partition_element> part_it(part_info->partitions); |
| 8893 | partition_element *part_elem; | ||
| 8894 | |||
| 8895 |
2/2✓ Branch 0 taken 17305 times.
✓ Branch 1 taken 7012 times.
|
24317 | while ((part_elem = part_it++)) { |
| 8896 |
2/2✓ Branch 0 taken 29 times.
✓ Branch 1 taken 17276 times.
|
17305 | if (part_elem->part_comment) { |
| 8897 | 29 | size_t comment_len = strlen(part_elem->part_comment); | |
| 8898 | |||
| 8899 | // Validate partition comment string | ||
| 8900 | 29 | std::string invalid_sub_str; | |
| 8901 |
2/4✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 29 times.
|
29 | if (is_invalid_string({part_elem->part_comment, comment_len}, |
| 8902 | system_charset_info, invalid_sub_str)) { | ||
| 8903 | ✗ | my_error(ER_COMMENT_CONTAINS_INVALID_STRING, MYF(0), "partition", | |
| 8904 | ✗ | (std::string(db) + "." + std::string(error_table_name) + | |
| 8905 | ✗ | "." + std::string(part_elem->partition_name)) | |
| 8906 | .c_str(), | ||
| 8907 | system_charset_info->csname, invalid_sub_str.c_str()); | ||
| 8908 | ✗ | return true; | |
| 8909 | } | ||
| 8910 | |||
| 8911 |
2/4✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 29 times.
|
29 | if (validate_comment_length(thd, part_elem->part_comment, &comment_len, |
| 8912 | TABLE_PARTITION_COMMENT_MAXLEN, | ||
| 8913 | ER_TOO_LONG_TABLE_PARTITION_COMMENT, | ||
| 8914 | part_elem->partition_name)) | ||
| 8915 | ✗ | return true; | |
| 8916 | 29 | part_elem->part_comment[comment_len] = '\0'; | |
| 8917 |
1/2✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
|
29 | } |
| 8918 |
2/2✓ Branch 0 taken 2215 times.
✓ Branch 1 taken 15090 times.
|
17305 | if (part_elem->subpartitions.elements) { |
| 8919 |
1/2✓ Branch 0 taken 2215 times.
✗ Branch 1 not taken.
|
2215 | List_iterator<partition_element> sub_it(part_elem->subpartitions); |
| 8920 | partition_element *subpart_elem; | ||
| 8921 |
2/2✓ Branch 0 taken 5194 times.
✓ Branch 1 taken 2215 times.
|
7409 | while ((subpart_elem = sub_it++)) { |
| 8922 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 5183 times.
|
5194 | if (subpart_elem->part_comment) { |
| 8923 | 11 | size_t comment_len = strlen(subpart_elem->part_comment); | |
| 8924 | |||
| 8925 | // Validate subpartition comment string | ||
| 8926 | 11 | std::string invalid_sub_str; | |
| 8927 |
2/4✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
|
11 | if (is_invalid_string({subpart_elem->part_comment, comment_len}, |
| 8928 | system_charset_info, invalid_sub_str)) { | ||
| 8929 | ✗ | my_error(ER_COMMENT_CONTAINS_INVALID_STRING, MYF(0), | |
| 8930 | "subpartition", | ||
| 8931 | ✗ | (std::string(db) + "." + std::string(error_table_name) + | |
| 8932 | ✗ | "." + std::string(part_elem->partition_name) + "." + | |
| 8933 | ✗ | std::string(subpart_elem->partition_name)) | |
| 8934 | .c_str(), | ||
| 8935 | system_charset_info->csname, invalid_sub_str.c_str()); | ||
| 8936 | ✗ | return true; | |
| 8937 | } | ||
| 8938 | |||
| 8939 |
2/4✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
|
11 | if (validate_comment_length(thd, subpart_elem->part_comment, |
| 8940 | &comment_len, | ||
| 8941 | TABLE_PARTITION_COMMENT_MAXLEN, | ||
| 8942 | ER_TOO_LONG_TABLE_PARTITION_COMMENT, | ||
| 8943 | subpart_elem->partition_name)) | ||
| 8944 | ✗ | return true; | |
| 8945 | 11 | subpart_elem->part_comment[comment_len] = '\0'; | |
| 8946 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
11 | } |
| 8947 | } | ||
| 8948 | } | ||
| 8949 | } | ||
| 8950 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 7009 times.
|
7012 | if (create_info->options & HA_LEX_CREATE_TMP_TABLE) { |
| 8951 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | my_error(ER_PARTITION_NO_TEMPORARY, MYF(0)); |
| 8952 | 3 | return true; | |
| 8953 | } | ||
| 8954 |
2/2✓ Branch 0 taken 1650 times.
✓ Branch 1 taken 5359 times.
|
7009 | if (create_info->used_fields & HA_CREATE_USED_ENGINE) { |
| 8955 | 1650 | part_info->default_engine_type = create_info->db_type; | |
| 8956 | } else { | ||
| 8957 |
2/2✓ Branch 0 taken 2433 times.
✓ Branch 1 taken 2926 times.
|
5359 | if (part_info->default_engine_type == nullptr) { |
| 8958 | 2433 | part_info->default_engine_type = | |
| 8959 |
1/2✓ Branch 0 taken 2433 times.
✗ Branch 1 not taken.
|
2433 | ha_checktype(thd, DB_TYPE_DEFAULT, false, false); |
| 8960 | } | ||
| 8961 | } | ||
| 8962 |
3/12✓ Branch 0 taken 7009 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7009 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 7009 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
7009 | DBUG_PRINT("info", |
| 8963 | ("db_type = %s create_info->db_type = %s", | ||
| 8964 | ha_resolve_storage_engine_name(part_info->default_engine_type), | ||
| 8965 | ha_resolve_storage_engine_name(create_info->db_type))); | ||
| 8966 |
3/4✓ Branch 0 taken 7009 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 541 times.
✓ Branch 3 taken 6468 times.
|
7009 | if (part_info->check_partition_info(thd, &engine_type, file.get(), |
| 8967 | create_info, false)) | ||
| 8968 | 541 | return true; | |
| 8969 | 6468 | part_info->default_engine_type = engine_type; | |
| 8970 | |||
| 8971 |
2/2✓ Branch 0 taken 17 times.
✓ Branch 1 taken 6451 times.
|
6468 | if (!engine_type->partition_flags) { |
| 8972 | /* | ||
| 8973 | The handler assigned to the table cannot handle partitioning. | ||
| 8974 | */ | ||
| 8975 |
1/2✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
|
17 | my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "native partitioning"); |
| 8976 | 17 | return true; | |
| 8977 | } | ||
| 8978 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6448 times.
|
6451 | if (create_info->db_type != engine_type) { |
| 8979 | /* | ||
| 8980 | We come here when we don't use a partitioned handler. | ||
| 8981 | Since we use a partitioned table it must be "native partitioned". | ||
| 8982 | We have switched engine from defaults, most likely only specified | ||
| 8983 | engines in partition clauses. | ||
| 8984 | */ | ||
| 8985 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | file.reset(get_new_handler((TABLE_SHARE *)nullptr, true, thd->mem_root, |
| 8986 | engine_type)); | ||
| 8987 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (file.get() == nullptr) { |
| 8988 | ✗ | mem_alloc_error(sizeof(handler)); | |
| 8989 | ✗ | return true; | |
| 8990 | } | ||
| 8991 | 3 | create_info->db_type = engine_type; | |
| 8992 | } | ||
| 8993 |
5/6✓ Branch 0 taken 6451 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 32 times.
✓ Branch 3 taken 6419 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 6448 times.
|
6483 | if (alter_info->has_compressed_columns() && |
| 8994 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 29 times.
|
32 | !ha_check_storage_engine_flag(part_info->default_engine_type, |
| 8995 | HTON_SUPPORTS_COMPRESSED_COLUMNS)) { | ||
| 8996 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | my_error(ER_ILLEGAL_HA_CREATE_OPTION, MYF(0), |
| 8997 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | ha_resolve_storage_engine_name(part_info->default_engine_type), |
| 8998 | "COMPRESSED COLUMNS"); | ||
| 8999 | 3 | return true; | |
| 9000 | } | ||
| 9001 | } | ||
| 9002 | |||
| 9003 | 758809 | Table_exists_result ter = check_if_table_exists( | |
| 9004 | thd, db, table_name, alias, | ||
| 9005 | 758809 | (create_info->options & HA_LEX_CREATE_TMP_TABLE), | |
| 9006 |
1/2✓ Branch 0 taken 758812 times.
✗ Branch 1 not taken.
|
758809 | (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS), internal_tmp_table); |
| 9007 |
2/2✓ Branch 0 taken 1104 times.
✓ Branch 1 taken 757708 times.
|
758812 | if (ter.m_error) { |
| 9008 | 1104 | return true; | |
| 9009 | } | ||
| 9010 |
2/2✓ Branch 0 taken 5324 times.
✓ Branch 1 taken 752384 times.
|
757708 | if (ter.m_table_exists) { |
| 9011 | 5324 | return false; | |
| 9012 | } | ||
| 9013 | |||
| 9014 | /* Suppress key length errors if this is a white listed table. */ | ||
| 9015 | 752384 | Key_length_error_handler error_handler; | |
| 9016 | bool is_whitelisted_table = | ||
| 9017 | 752384 | (create_info->options & HA_LEX_CREATE_TMP_TABLE) != | |
| 9018 |
2/2✓ Branch 0 taken 658197 times.
✓ Branch 1 taken 41715 times.
|
699912 | HA_LEX_CREATE_TMP_TABLE && |
| 9019 | 699912 | (thd->is_server_upgrade_thread() || | |
| 9020 |
4/4✓ Branch 0 taken 699912 times.
✓ Branch 1 taken 52472 times.
✓ Branch 2 taken 546708 times.
✓ Branch 3 taken 111489 times.
|
1999004 | create_info->db_type->db_type == DB_TYPE_INNODB) && |
| 9021 |
8/16✓ Branch 0 taken 588423 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 588423 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 588423 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 588423 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 182071 times.
✓ Branch 9 taken 406352 times.
✓ Branch 10 taken 588423 times.
✓ Branch 11 taken 163964 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
|
1340810 | (dd::get_dictionary()->is_dd_table_name(db, error_table_name) || |
| 9022 |
12/20✓ Branch 0 taken 182071 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 182071 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 182071 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 182071 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 51954 times.
✓ Branch 9 taken 130117 times.
✓ Branch 10 taken 182071 times.
✓ Branch 11 taken 570313 times.
✓ Branch 12 taken 182068 times.
✓ Branch 13 taken 570316 times.
✓ Branch 14 taken 588423 times.
✓ Branch 15 taken 163964 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
|
934455 | dd::get_dictionary()->is_system_table_name(db, error_table_name)); |
| 9023 |
3/4✓ Branch 0 taken 458306 times.
✓ Branch 1 taken 294081 times.
✓ Branch 2 taken 458306 times.
✗ Branch 3 not taken.
|
752387 | if (is_whitelisted_table) thd->push_internal_handler(&error_handler); |
| 9024 | |||
| 9025 |
1/2✓ Branch 0 taken 752382 times.
✗ Branch 1 not taken.
|
752387 | bool prepare_error = mysql_prepare_create_table( |
| 9026 | thd, db, error_table_name, create_info, alter_info, file.get(), | ||
| 9027 | (part_info != nullptr), key_info, key_count, fk_key_info, fk_key_count, | ||
| 9028 | existing_fk_info, existing_fk_count, existing_fk_table, | ||
| 9029 | fk_max_generated_name_number, select_field_count, find_parent_keys); | ||
| 9030 | |||
| 9031 |
3/4✓ Branch 0 taken 458306 times.
✓ Branch 1 taken 294076 times.
✓ Branch 2 taken 458306 times.
✗ Branch 3 not taken.
|
752382 | if (is_whitelisted_table) thd->pop_internal_handler(); |
| 9032 | |||
| 9033 |
2/2✓ Branch 0 taken 8960 times.
✓ Branch 1 taken 743422 times.
|
752382 | if (prepare_error) return true; |
| 9034 | |||
| 9035 |
1/2✓ Branch 0 taken 743417 times.
✗ Branch 1 not taken.
|
743422 | THD_STAGE_INFO(thd, stage_creating_table); |
| 9036 | |||
| 9037 | { | ||
| 9038 | size_t dirlen; | ||
| 9039 | char dirpath[FN_REFLEN]; | ||
| 9040 | |||
| 9041 | /* | ||
| 9042 | data_file_name and index_file_name include the table name without | ||
| 9043 | extension. Mostly this does not refer to an existing file. When | ||
| 9044 | comparing data_file_name or index_file_name against the data | ||
| 9045 | directory, we try to resolve all symbolic links. On some systems, | ||
| 9046 | we use realpath(3) for the resolution. This returns ENOENT if the | ||
| 9047 | resolved path does not refer to an existing file. my_realpath() | ||
| 9048 | does then copy the requested path verbatim, without symlink | ||
| 9049 | resolution. Thereafter the comparison can fail even if the | ||
| 9050 | requested path is within the data directory. E.g. if symlinks to | ||
| 9051 | another file system are used. To make realpath(3) return the | ||
| 9052 | resolved path, we strip the table name and compare the directory | ||
| 9053 | path only. If the directory doesn't exist either, table creation | ||
| 9054 | will fail anyway. | ||
| 9055 | */ | ||
| 9056 |
2/2✓ Branch 0 taken 236 times.
✓ Branch 1 taken 743181 times.
|
743417 | if (create_info->data_file_name) { |
| 9057 |
1/2✓ Branch 0 taken 236 times.
✗ Branch 1 not taken.
|
236 | dirname_part(dirpath, create_info->data_file_name, &dirlen); |
| 9058 |
3/4✓ Branch 0 taken 236 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 230 times.
|
236 | if (test_if_data_home_dir(dirpath)) { |
| 9059 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | my_error(ER_WRONG_ARGUMENTS, MYF(0), "DATA DIRECTORY"); |
| 9060 | 9 | return true; | |
| 9061 | } | ||
| 9062 | } | ||
| 9063 |
2/2✓ Branch 0 taken 25 times.
✓ Branch 1 taken 743386 times.
|
743411 | if (create_info->index_file_name) { |
| 9064 |
1/2✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
|
25 | dirname_part(dirpath, create_info->index_file_name, &dirlen); |
| 9065 |
3/4✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 22 times.
|
25 | if (test_if_data_home_dir(dirpath)) { |
| 9066 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | my_error(ER_WRONG_ARGUMENTS, MYF(0), "INDEX DIRECTORY"); |
| 9067 | 3 | return true; | |
| 9068 | } | ||
| 9069 | } | ||
| 9070 | } | ||
| 9071 | |||
| 9072 |
3/4✓ Branch 0 taken 743398 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 743393 times.
|
743408 | if (check_partition_dirs(thd->lex->part_info)) return true; |
| 9073 | |||
| 9074 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 743385 times.
|
743393 | if (thd->variables.sql_mode & MODE_NO_DIR_IN_CREATE) { |
| 9075 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
|
8 | if (create_info->data_file_name) |
| 9076 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | push_warning_printf(thd, Sql_condition::SL_WARNING, WARN_OPTION_IGNORED, |
| 9077 | ER_THD(thd, WARN_OPTION_IGNORED), "DATA DIRECTORY"); | ||
| 9078 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7 times.
|
8 | if (create_info->index_file_name) |
| 9079 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | push_warning_printf(thd, Sql_condition::SL_WARNING, WARN_OPTION_IGNORED, |
| 9080 | ER_THD(thd, WARN_OPTION_IGNORED), "INDEX DIRECTORY"); | ||
| 9081 | 8 | create_info->data_file_name = create_info->index_file_name = nullptr; | |
| 9082 | } | ||
| 9083 | |||
| 9084 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 743392 times.
|
743393 | if (thd->variables.keep_files_on_create) |
| 9085 | 1 | create_info->options |= HA_CREATE_KEEP_FILES; | |
| 9086 | |||
| 9087 | /* | ||
| 9088 | Create table definitions. | ||
| 9089 | If "no_ha_table" is false also create table in storage engine. | ||
| 9090 | */ | ||
| 9091 |
2/2✓ Branch 0 taken 52459 times.
✓ Branch 1 taken 690934 times.
|
743393 | if (create_info->options & HA_LEX_CREATE_TMP_TABLE) { |
| 9092 |
2/2✓ Branch 0 taken 111 times.
✓ Branch 1 taken 52347 times.
|
104917 | if (rea_create_tmp_table(thd, path, schema, db, table_name, create_info, |
| 9093 | 52460 | alter_info->create_list, *key_count, *key_info, | |
| 9094 | keys_onoff, | ||
| 9095 |
1/2✓ Branch 0 taken 52458 times.
✗ Branch 1 not taken.
|
52460 | &alter_info->check_constraint_spec_list, |
| 9096 | file.get(), no_ha_table, is_trans, table_def)) | ||
| 9097 | 111 | return true; | |
| 9098 | } else { | ||
| 9099 |
2/2✓ Branch 0 taken 1191 times.
✓ Branch 1 taken 689736 times.
|
1381861 | if (rea_create_base_table(thd, path, schema, db, table_name, create_info, |
| 9100 | 690940 | alter_info->create_list, *key_count, *key_info, | |
| 9101 | keys_onoff, *fk_key_count, *fk_key_info, | ||
| 9102 |
1/2✓ Branch 0 taken 690927 times.
✗ Branch 1 not taken.
|
690940 | &alter_info->check_constraint_spec_list, |
| 9103 | file.get(), no_ha_table, do_not_store_in_dd, | ||
| 9104 | part_info, is_trans, table_def, post_ddl_ht)) | ||
| 9105 | 1191 | return true; | |
| 9106 | } | ||
| 9107 | |||
| 9108 |
1/2✓ Branch 0 taken 742083 times.
✗ Branch 1 not taken.
|
742083 | THD_STAGE_INFO(thd, stage_after_create); |
| 9109 |
6/6✓ Branch 0 taken 52347 times.
✓ Branch 1 taken 689736 times.
✓ Branch 2 taken 2314 times.
✓ Branch 3 taken 50033 times.
✓ Branch 4 taken 2314 times.
✓ Branch 5 taken 739769 times.
|
794430 | if ((create_info->options & HA_LEX_CREATE_TMP_TABLE) && |
| 9110 | 52347 | thd->in_multi_stmt_transaction_mode()) { | |
| 9111 | /* | ||
| 9112 | When autocommit is disabled, creating temporary table sets this | ||
| 9113 | flag to start transaction in any case (regardless of binlog=on/off, | ||
| 9114 | binlog format and transactional/non-transactional engine) to make | ||
| 9115 | behavior consistent. | ||
| 9116 | */ | ||
| 9117 | 2314 | thd->server_status |= SERVER_STATUS_IN_TRANS; | |
| 9118 | } | ||
| 9119 | 742083 | return false; | |
| 9120 | 759411 | } | |
| 9121 | |||
| 9122 | /* | ||
| 9123 | This function disallows requests to use general tablespace for the table | ||
| 9124 | with ENCRYPTION clause different from the general tablespace's encryption | ||
| 9125 | type. | ||
| 9126 | |||
| 9127 | @param thd Thread | ||
| 9128 | @param create_info Metadata of the table. | ||
| 9129 | |||
| 9130 | @returns true on failure, false on success. | ||
| 9131 | */ | ||
| 9132 | 707096 | static bool validate_table_encryption(THD *thd, HA_CREATE_INFO *create_info) { | |
| 9133 | // Study if this table uses general tablespaces and if any one is encrypted. | ||
| 9134 | 707096 | bool uses_general_tablespace = false; | |
| 9135 | 707096 | bool uses_encrypted_tablespace = false; | |
| 9136 | 707096 | bool uses_system_tablespace = false; | |
| 9137 | dd::Encrypt_result result = | ||
| 9138 |
1/2✓ Branch 0 taken 707110 times.
✗ Branch 1 not taken.
|
707096 | dd::is_tablespace_encrypted(thd, create_info, &uses_general_tablespace); |
| 9139 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 707104 times.
|
707110 | if (result.error) return true; |
| 9140 | |||
| 9141 |
2/2✓ Branch 0 taken 453030 times.
✓ Branch 1 taken 254074 times.
|
707104 | if (uses_general_tablespace) { |
| 9142 | 453030 | uses_encrypted_tablespace = result.value; | |
| 9143 |
2/2✓ Branch 0 taken 252738 times.
✓ Branch 1 taken 1336 times.
|
254074 | } else if (!create_info->tablespace && |
| 9144 |
2/2✓ Branch 0 taken 133680 times.
✓ Branch 1 taken 119058 times.
|
252738 | create_info->db_type->get_tablespace_type_by_name) { |
| 9145 | /* | ||
| 9146 | No tablespace is explicitly specified. InnoDB can either use | ||
| 9147 | file-per-table or general tablespace based on 'innodb_file_per_table' | ||
| 9148 | setting, so ask SE about it. | ||
| 9149 | */ | ||
| 9150 | Tablespace_type tt; | ||
| 9151 |
2/4✓ Branch 0 taken 133683 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 133683 times.
|
133680 | if (create_info->db_type->get_tablespace_type_by_name( |
| 9152 | create_info->tablespace, &tt)) { | ||
| 9153 | ✗ | return true; | |
| 9154 | } | ||
| 9155 |
2/2✓ Branch 0 taken 432 times.
✓ Branch 1 taken 133251 times.
|
134115 | uses_general_tablespace = (tt != Tablespace_type::SPACE_TYPE_IMPLICIT && |
| 9156 |
1/2✓ Branch 0 taken 432 times.
✗ Branch 1 not taken.
|
432 | tt != Tablespace_type::SPACE_TYPE_SHARED); |
| 9157 | 133683 | uses_system_tablespace = tt == Tablespace_type::SPACE_TYPE_SYSTEM; | |
| 9158 |
2/2✓ Branch 0 taken 432 times.
✓ Branch 1 taken 133251 times.
|
133683 | if (uses_system_tablespace) { |
| 9159 |
1/2✓ Branch 0 taken 432 times.
✗ Branch 1 not taken.
|
432 | dd::Encrypt_result result2 = dd::is_system_tablespace_encrypted(thd); |
| 9160 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 432 times.
|
432 | if (result2.error) return true; |
| 9161 | 432 | uses_encrypted_tablespace = result2.value; | |
| 9162 | } | ||
| 9163 | } | ||
| 9164 | |||
| 9165 | /* | ||
| 9166 | Stop if table's uses general tablespace and the requested encryption | ||
| 9167 | type does not match the general tablespace encryption type. | ||
| 9168 | We allow to create table inside encrypted tablespace when ONLINE_TO_KEYRING | ||
| 9169 | is specified. This table will be created in encrypted tablespace - which we | ||
| 9170 | aim for and can be rotated to Keyring (given encryption threads are ON). | ||
| 9171 | */ | ||
| 9172 |
1/2✓ Branch 0 taken 707103 times.
✗ Branch 1 not taken.
|
707107 | bool requested_type = dd::is_encrypted(create_info->encrypt_type); |
| 9173 | |||
| 9174 |
5/6✓ Branch 0 taken 253641 times.
✓ Branch 1 taken 453462 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 253641 times.
✓ Branch 4 taken 200 times.
✓ Branch 5 taken 453262 times.
|
707103 | if ((uses_general_tablespace || uses_system_tablespace) && |
| 9175 | 200 | ((requested_type != uses_encrypted_tablespace) && | |
| 9176 |
2/2✓ Branch 0 taken 26 times.
✓ Branch 1 taken 174 times.
|
200 | (!uses_encrypted_tablespace || |
| 9177 |
1/2✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
|
26 | global_system_variables.default_table_encryption != |
| 9178 | DEFAULT_TABLE_ENC_ONLINE_TO_KEYRING))) { | ||
| 9179 |
5/6✓ Branch 0 taken 26 times.
✓ Branch 1 taken 174 times.
✓ Branch 2 taken 174 times.
✓ Branch 3 taken 26 times.
✓ Branch 4 taken 200 times.
✗ Branch 5 not taken.
|
200 | my_error(ER_INVALID_ENCRYPTION_REQUEST, MYF(0), |
| 9180 | requested_type ? "'encrypted'" : "'unencrypted'", | ||
| 9181 | uses_encrypted_tablespace ? "'encrypted'" : "'unencrypted'"); | ||
| 9182 | 200 | return true; | |
| 9183 | } | ||
| 9184 | |||
| 9185 | 706903 | return false; | |
| 9186 | } | ||
| 9187 | |||
| 9188 | 5538587 | static void warn_on_deprecated_float_auto_increment( | |
| 9189 | THD *thd, const Create_field &sql_field) { | ||
| 9190 |
2/2✓ Branch 0 taken 239346 times.
✓ Branch 1 taken 5299241 times.
|
5538587 | if ((sql_field.flags & AUTO_INCREMENT_FLAG) && |
| 9191 |
2/2✓ Branch 0 taken 239339 times.
✓ Branch 1 taken 7 times.
|
239346 | (sql_field.sql_type == MYSQL_TYPE_FLOAT || |
| 9192 |
2/2✓ Branch 0 taken 22 times.
✓ Branch 1 taken 239317 times.
|
239339 | sql_field.sql_type == MYSQL_TYPE_DOUBLE)) { |
| 9193 | 29 | push_warning_printf(thd, Sql_condition::SL_WARNING, | |
| 9194 | ER_WARN_DEPRECATED_FLOAT_AUTO_INCREMENT, | ||
| 9195 | ER_THD(thd, ER_WARN_DEPRECATED_FLOAT_AUTO_INCREMENT), | ||
| 9196 | 29 | sql_field.field_name); | |
| 9197 | } | ||
| 9198 | 5538587 | } | |
| 9199 | |||
| 9200 | 58208 | static void warn_on_deprecated_float_precision(THD *thd, | |
| 9201 | const Create_field &sql_field) { | ||
| 9202 |
2/2✓ Branch 0 taken 41021 times.
✓ Branch 1 taken 17187 times.
|
58208 | if (sql_field.decimals != DECIMAL_NOT_SPECIFIED) { |
| 9203 |
2/2✓ Branch 0 taken 41016 times.
✓ Branch 1 taken 5 times.
|
41021 | if (sql_field.sql_type == MYSQL_TYPE_FLOAT || |
| 9204 |
2/2✓ Branch 0 taken 57 times.
✓ Branch 1 taken 40959 times.
|
41016 | sql_field.sql_type == MYSQL_TYPE_DOUBLE) { |
| 9205 | 62 | push_warning(thd, Sql_condition::SL_WARNING, | |
| 9206 | ER_WARN_DEPRECATED_SYNTAX_NO_REPLACEMENT, | ||
| 9207 | ER_THD(thd, ER_WARN_DEPRECATED_FLOAT_DIGITS)); | ||
| 9208 | } | ||
| 9209 | } | ||
| 9210 | 58208 | } | |
| 9211 | |||
| 9212 | 58208 | static void warn_on_deprecated_float_unsigned(THD *thd, | |
| 9213 | const Create_field &sql_field) { | ||
| 9214 |
2/2✓ Branch 0 taken 20684 times.
✓ Branch 1 taken 37524 times.
|
58208 | if ((sql_field.flags & UNSIGNED_FLAG) && |
| 9215 |
2/2✓ Branch 0 taken 20680 times.
✓ Branch 1 taken 4 times.
|
20684 | (sql_field.sql_type == MYSQL_TYPE_FLOAT || |
| 9216 |
2/2✓ Branch 0 taken 20674 times.
✓ Branch 1 taken 6 times.
|
20680 | sql_field.sql_type == MYSQL_TYPE_DOUBLE || |
| 9217 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 20666 times.
|
20674 | sql_field.sql_type == MYSQL_TYPE_NEWDECIMAL)) { |
| 9218 | 18 | push_warning(thd, Sql_condition::SL_WARNING, | |
| 9219 | ER_WARN_DEPRECATED_SYNTAX_NO_REPLACEMENT, | ||
| 9220 | ER_THD(thd, ER_WARN_DEPRECATED_FLOAT_UNSIGNED)); | ||
| 9221 | } | ||
| 9222 | 58208 | } | |
| 9223 | |||
| 9224 | 58208 | static void warn_on_deprecated_zerofill(THD *thd, | |
| 9225 | const Create_field &sql_field) { | ||
| 9226 | // The YEAR data type is implicitly ZEROFILL. Should only warn if it has been | ||
| 9227 | // declared explicitly as ZEROFILL, but that cannot be determined at this | ||
| 9228 | // point, so suppress the warning to avoid confusion. | ||
| 9229 |
2/2✓ Branch 0 taken 17 times.
✓ Branch 1 taken 58191 times.
|
58208 | if (sql_field.sql_type == MYSQL_TYPE_YEAR) return; |
| 9230 | |||
| 9231 |
2/2✓ Branch 0 taken 29 times.
✓ Branch 1 taken 58162 times.
|
58191 | if (sql_field.flags & ZEROFILL_FLAG) |
| 9232 | 29 | push_warning(thd, Sql_condition::SL_WARNING, | |
| 9233 | ER_WARN_DEPRECATED_SYNTAX_NO_REPLACEMENT, | ||
| 9234 | ER_THD(thd, ER_WARN_DEPRECATED_ZEROFILL)); | ||
| 9235 | } | ||
| 9236 | |||
| 9237 | /** | ||
| 9238 | Simple wrapper around create_table_impl() to be used | ||
| 9239 | in various version of CREATE TABLE statement. | ||
| 9240 | */ | ||
| 9241 | 671438 | bool mysql_create_table_no_lock(THD *thd, const char *db, | |
| 9242 | const char *table_name, | ||
| 9243 | HA_CREATE_INFO *create_info, | ||
| 9244 | Alter_info *alter_info, uint select_field_count, | ||
| 9245 | bool find_parent_keys, bool *is_trans, | ||
| 9246 | handlerton **post_ddl_ht) { | ||
| 9247 | KEY *not_used_1; | ||
| 9248 | uint not_used_2; | ||
| 9249 | 671438 | FOREIGN_KEY *not_used_3 = nullptr; | |
| 9250 | 671438 | uint not_used_4 = 0; | |
| 9251 | 671438 | std::unique_ptr<dd::Table> not_used_5; | |
| 9252 | char path[FN_REFLEN + 1]; | ||
| 9253 | |||
| 9254 |
2/2✓ Branch 0 taken 51391 times.
✓ Branch 1 taken 620047 times.
|
671438 | if (create_info->options & HA_LEX_CREATE_TMP_TABLE) |
| 9255 |
1/2✓ Branch 0 taken 51386 times.
✗ Branch 1 not taken.
|
51391 | build_tmptable_filename(thd, path, sizeof(path)); |
| 9256 | else { | ||
| 9257 | bool was_truncated; | ||
| 9258 |
1/2✓ Branch 0 taken 620045 times.
✗ Branch 1 not taken.
|
620047 | const char *alias = table_case_name(create_info, table_name); |
| 9259 |
1/2✓ Branch 0 taken 620051 times.
✗ Branch 1 not taken.
|
620045 | build_table_filename(path, sizeof(path) - 1 - reg_ext_length, db, alias, "", |
| 9260 | 0, &was_truncated); | ||
| 9261 | // Check truncation, will lead to overflow when adding extension | ||
| 9262 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 620050 times.
|
620051 | if (was_truncated) { |
| 9263 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_IDENT_CAUSES_TOO_LONG_PATH, MYF(0), sizeof(path) - 1, path); |
| 9264 | 1 | return true; | |
| 9265 | } | ||
| 9266 | } | ||
| 9267 | |||
| 9268 | /* | ||
| 9269 | Don't create the DD tables in the DDSE unless installing the DD. | ||
| 9270 | */ | ||
| 9271 | |||
| 9272 | 671436 | bool no_ha_table = false; | |
| 9273 |
14/22✓ Branch 0 taken 614510 times.
✓ Branch 1 taken 56926 times.
✓ Branch 2 taken 614507 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 614511 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 614515 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 614514 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 393425 times.
✓ Branch 11 taken 221089 times.
✓ Branch 12 taken 614510 times.
✓ Branch 13 taken 56930 times.
✓ Branch 14 taken 614512 times.
✓ Branch 15 taken 56930 times.
✓ Branch 16 taken 393425 times.
✓ Branch 17 taken 278020 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
|
671436 | if (!opt_initialize && dd::get_dictionary()->is_dd_table_name(db, table_name)) |
| 9274 | 393425 | no_ha_table = true; | |
| 9275 | |||
| 9276 | // Check if the schema exists. We must make sure the schema is released | ||
| 9277 | // and unlocked in the right order. | ||
| 9278 | 671445 | dd::Schema_MDL_locker mdl_locker(thd); | |
| 9279 |
1/2✓ Branch 0 taken 671441 times.
✗ Branch 1 not taken.
|
671433 | dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client()); |
| 9280 | 671441 | const dd::Schema *schema = nullptr; | |
| 9281 |
9/16✓ Branch 0 taken 671435 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 671438 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 671442 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 671439 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 7 times.
✓ Branch 9 taken 671432 times.
✓ Branch 10 taken 671432 times.
✓ Branch 11 taken 4 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 671440 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
|
671441 | if (mdl_locker.ensure_locked(db) || thd->dd_client()->acquire(db, &schema)) { |
| 9282 | // Error is reported by the dictionary subsystem. | ||
| 9283 | ✗ | return true; | |
| 9284 | } | ||
| 9285 | |||
| 9286 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 671433 times.
|
671440 | if (schema == nullptr) { |
| 9287 |
1/2✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 | my_error(ER_BAD_DB_ERROR, MYF(0), db); |
| 9288 | 7 | return true; | |
| 9289 | } | ||
| 9290 | |||
| 9291 | // Fix create_info->explicit_encryption. For alter it is retrieved | ||
| 9292 | // from share. | ||
| 9293 |
2/2✓ Branch 0 taken 671431 times.
✓ Branch 1 taken 2 times.
|
671433 | if (!(create_info->options & HA_LEX_CREATE_INTERNAL_TMP_TABLE) && |
| 9294 |
2/2✓ Branch 0 taken 22131 times.
✓ Branch 1 taken 649300 times.
|
671431 | (create_info->used_fields & HA_CREATE_USED_ENCRYPT)) { |
| 9295 | 22131 | create_info->explicit_encryption = true; | |
| 9296 | } | ||
| 9297 | |||
| 9298 | // Do not accept AUTOEXTEND_SIZE clauses for | ||
| 9299 | // temporary table. | ||
| 9300 |
2/2✓ Branch 0 taken 51389 times.
✓ Branch 1 taken 620044 times.
|
671433 | if (create_info->options & HA_LEX_CREATE_TMP_TABLE) { |
| 9301 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 51388 times.
|
51389 | if (create_info->m_implicit_tablespace_autoextend_size > 0) { |
| 9302 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_CANNOT_USE_AUTOEXTEND_SIZE_CLAUSE, MYF(0), "temporary"); |
| 9303 | 1 | return true; | |
| 9304 | } | ||
| 9305 | } | ||
| 9306 | |||
| 9307 | // Determine table encryption type, and check if user is allowed to create. | ||
| 9308 |
2/2✓ Branch 0 taken 620035 times.
✓ Branch 1 taken 51397 times.
|
671432 | if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE)) { |
| 9309 | /* | ||
| 9310 | Assume table as encrypted, if user did not explicitly state it and | ||
| 9311 | we have a schema with default encryption enabled. | ||
| 9312 | */ | ||
| 9313 |
7/8✓ Branch 0 taken 597142 times.
✓ Branch 1 taken 22893 times.
✓ Branch 2 taken 597142 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 44 times.
✓ Branch 5 taken 597098 times.
✓ Branch 6 taken 44 times.
✓ Branch 7 taken 619991 times.
|
620035 | if (!create_info->encrypt_type.length && schema->default_encryption()) { |
| 9314 |
1/2✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
|
44 | create_info->encrypt_type = {strmake_root(thd->mem_root, "Y", 1), 1}; |
| 9315 | } | ||
| 9316 | |||
| 9317 | // Stop if it is invalid encryption clause, when using general tablespace. | ||
| 9318 |
3/4✓ Branch 0 taken 620035 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 105 times.
✓ Branch 3 taken 619930 times.
|
620035 | if (validate_table_encryption(thd, create_info)) return true; |
| 9319 | |||
| 9320 | // Check table encryption privilege | ||
| 9321 |
4/4✓ Branch 0 taken 597088 times.
✓ Branch 1 taken 22842 times.
✓ Branch 2 taken 407378 times.
✓ Branch 3 taken 189710 times.
|
619930 | if (create_info->encrypt_type.str || create_info->tablespace) { |
| 9322 | /* | ||
| 9323 | Check privilege only if request encryption type differ from schema | ||
| 9324 | default encryption type. | ||
| 9325 | */ | ||
| 9326 |
1/2✓ Branch 0 taken 430227 times.
✗ Branch 1 not taken.
|
430220 | bool request_type = dd::is_encrypted(create_info->encrypt_type); |
| 9327 |
3/4✓ Branch 0 taken 430216 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5691 times.
✓ Branch 3 taken 424525 times.
|
430227 | if (schema->default_encryption() != request_type) { |
| 9328 |
2/2✓ Branch 0 taken 35 times.
✓ Branch 1 taken 5656 times.
|
5691 | if (opt_table_encryption_privilege_check) { |
| 9329 |
3/4✓ Branch 0 taken 35 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✓ Branch 3 taken 16 times.
|
35 | if (check_table_encryption_admin_access(thd)) { |
| 9330 |
1/2✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
|
19 | my_error(ER_CANNOT_SET_TABLE_ENCRYPTION, MYF(0)); |
| 9331 | 19 | return true; | |
| 9332 | } | ||
| 9333 |
6/8✓ Branch 0 taken 5656 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 326 times.
✓ Branch 3 taken 5330 times.
✓ Branch 4 taken 326 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 326 times.
✓ Branch 7 taken 5330 times.
|
5656 | } else if (schema->default_encryption() && !request_type) { |
| 9334 |
2/4✓ Branch 0 taken 326 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 326 times.
✗ Branch 3 not taken.
|
326 | push_warning(thd, Sql_condition::SL_WARNING, |
| 9335 | WARN_UNENCRYPTED_TABLE_IN_ENCRYPTED_DB, | ||
| 9336 | ER_THD(thd, WARN_UNENCRYPTED_TABLE_IN_ENCRYPTED_DB)); | ||
| 9337 | } | ||
| 9338 | } | ||
| 9339 | } | ||
| 9340 | } | ||
| 9341 | |||
| 9342 |
5/8✓ Branch 0 taken 671297 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 671307 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6148823 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5477513 times.
✓ Branch 7 taken 671310 times.
|
6148815 | for (const Create_field &sql_field : alter_info->create_list) { |
| 9343 |
1/2✓ Branch 0 taken 5477511 times.
✗ Branch 1 not taken.
|
5477513 | warn_on_deprecated_float_auto_increment(thd, sql_field); |
| 9344 | } | ||
| 9345 | |||
| 9346 | // Only needed for CREATE TABLE LIKE / SELECT, as warnings for | ||
| 9347 | // pure CREATE TABLE is reported in the parser. | ||
| 9348 |
3/4✓ Branch 0 taken 671307 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9163 times.
✓ Branch 3 taken 662144 times.
|
671310 | if (!thd->lex->query_block->field_list_is_empty()) { |
| 9349 |
5/8✓ Branch 0 taken 9163 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9163 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 63584 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 54421 times.
✓ Branch 7 taken 9163 times.
|
63584 | for (const Create_field &sql_field : alter_info->create_list) { |
| 9350 |
1/2✓ Branch 0 taken 54421 times.
✗ Branch 1 not taken.
|
54421 | warn_on_deprecated_float_precision(thd, sql_field); |
| 9351 |
1/2✓ Branch 0 taken 54421 times.
✗ Branch 1 not taken.
|
54421 | warn_on_deprecated_float_unsigned(thd, sql_field); |
| 9352 |
1/2✓ Branch 0 taken 54421 times.
✗ Branch 1 not taken.
|
54421 | warn_on_deprecated_zerofill(thd, sql_field); |
| 9353 | } | ||
| 9354 | } | ||
| 9355 | |||
| 9356 |
2/2✓ Branch 0 taken 17307 times.
✓ Branch 1 taken 654002 times.
|
671307 | if (thd->is_plugin_fake_ddl()) no_ha_table = true; |
| 9357 | |||
| 9358 |
1/2✓ Branch 0 taken 671285 times.
✗ Branch 1 not taken.
|
671309 | return create_table_impl( |
| 9359 | thd, *schema, db, table_name, table_name, path, create_info, alter_info, | ||
| 9360 | false, select_field_count, find_parent_keys, no_ha_table, false, is_trans, | ||
| 9361 | ¬_used_1, ¬_used_2, Alter_info::ENABLE, ¬_used_3, ¬_used_4, | ||
| 9362 | 671285 | nullptr, 0, nullptr, 0, ¬_used_5, post_ddl_ht); | |
| 9363 | 671418 | } | |
| 9364 | |||
| 9365 | typedef std::set<std::pair<dd::String_type, dd::String_type>> | ||
| 9366 | Normalized_fk_children; | ||
| 9367 | |||
| 9368 | /** | ||
| 9369 | Fetch names of all tables having a FK referring to the given table. | ||
| 9370 | |||
| 9371 | @param thd Thread handle. | ||
| 9372 | @param parent_schema Schema name of the referenced table. | ||
| 9373 | @param parent_name Name of the referenced table. | ||
| 9374 | @param parent_engine Name of the referenced table's storage engine. | ||
| 9375 | @param [out] fk_children Set of unique schema qualified names of | ||
| 9376 | tables referring the given parent. | ||
| 9377 | |||
| 9378 | The children are fetched from the DD tables using uncommitted read. The | ||
| 9379 | names are normalized, i.e., if l_c_t_n == 2, the names are lowercased. | ||
| 9380 | |||
| 9381 | @retval operation outcome, false if no error. | ||
| 9382 | */ | ||
| 9383 | |||
| 9384 | 290998 | static bool fetch_fk_children_uncached_uncommitted_normalized( | |
| 9385 | THD *thd, const char *parent_schema, const char *parent_name, | ||
| 9386 | const char *parent_engine, Normalized_fk_children *fk_children) { | ||
| 9387 | 290998 | std::vector<dd::String_type> children_dbs, children_names; | |
| 9388 | |||
| 9389 |
5/10✓ Branch 0 taken 290996 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 291009 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 291008 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 291007 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 291010 times.
|
291008 | if (thd->dd_client()->fetch_fk_children_uncached( |
| 9390 | parent_schema, parent_name, parent_engine, true, &children_dbs, | ||
| 9391 | &children_names)) | ||
| 9392 | ✗ | return true; | |
| 9393 | |||
| 9394 | 291010 | auto db_it = children_dbs.begin(); | |
| 9395 | 291008 | auto names_it = children_names.begin(); | |
| 9396 | |||
| 9397 |
2/2✓ Branch 0 taken 1858 times.
✓ Branch 1 taken 291008 times.
|
292867 | while (db_it != children_dbs.end()) { |
| 9398 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1858 times.
|
1858 | assert(names_it != children_names.end()); |
| 9399 | char buff_db[NAME_LEN + 1]; | ||
| 9400 | char buff_table[NAME_LEN + 1]; | ||
| 9401 | 1858 | my_stpncpy(buff_db, db_it->c_str(), NAME_LEN); | |
| 9402 | 1858 | my_stpncpy(buff_table, names_it->c_str(), NAME_LEN); | |
| 9403 | /* | ||
| 9404 | In lower-case-table-names == 2 mode we store original versions of table | ||
| 9405 | and db names in the data-dictionary. Hence they need to be lowercased | ||
| 9406 | to produce correct MDL key for them and for other uses. | ||
| 9407 | */ | ||
| 9408 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1858 times.
|
1858 | if (lower_case_table_names == 2) { |
| 9409 | ✗ | my_casedn_str(system_charset_info, buff_db); | |
| 9410 | ✗ | my_casedn_str(system_charset_info, buff_table); | |
| 9411 | } | ||
| 9412 | |||
| 9413 |
1/2✓ Branch 0 taken 1858 times.
✗ Branch 1 not taken.
|
1858 | fk_children->insert( |
| 9414 |
1/2✓ Branch 0 taken 1858 times.
✗ Branch 1 not taken.
|
3716 | typename Normalized_fk_children::value_type(buff_db, buff_table)); |
| 9415 | |||
| 9416 | 1858 | ++db_it; | |
| 9417 | 1858 | ++names_it; | |
| 9418 | } | ||
| 9419 | 291008 | return false; | |
| 9420 | 291008 | } | |
| 9421 | |||
| 9422 | 114993 | bool collect_fk_children(THD *thd, const char *db, const char *arg_table_name, | |
| 9423 | handlerton *hton, enum_mdl_type lock_type, | ||
| 9424 | MDL_request_list *mdl_requests) { | ||
| 9425 | 114993 | Normalized_fk_children fk_children; | |
| 9426 |
3/6✓ Branch 0 taken 115008 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 115007 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 115007 times.
|
115006 | if (fetch_fk_children_uncached_uncommitted_normalized( |
| 9427 | thd, db, arg_table_name, ha_resolve_storage_engine_name(hton), | ||
| 9428 | &fk_children)) | ||
| 9429 | ✗ | return true; | |
| 9430 | |||
| 9431 |
3/4✓ Branch 0 taken 731 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 731 times.
✓ Branch 3 taken 115007 times.
|
115738 | for (auto fk_children_it : fk_children) { |
| 9432 | 731 | const char *schema_name = fk_children_it.first.c_str(); | |
| 9433 | 731 | const char *table_name = fk_children_it.second.c_str(); | |
| 9434 | |||
| 9435 |
1/2✓ Branch 0 taken 731 times.
✗ Branch 1 not taken.
|
731 | MDL_request *mdl_request = new (thd->mem_root) MDL_request; |
| 9436 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 731 times.
|
731 | if (mdl_request == nullptr) return true; |
| 9437 | |||
| 9438 |
1/2✓ Branch 0 taken 731 times.
✗ Branch 1 not taken.
|
731 | MDL_REQUEST_INIT(mdl_request, MDL_key::TABLE, schema_name, table_name, |
| 9439 | lock_type, MDL_STATEMENT); | ||
| 9440 |
1/2✓ Branch 0 taken 731 times.
✗ Branch 1 not taken.
|
731 | mdl_requests->push_front(mdl_request); |
| 9441 | |||
| 9442 |
1/2✓ Branch 0 taken 731 times.
✗ Branch 1 not taken.
|
731 | mdl_request = new (thd->mem_root) MDL_request; |
| 9443 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 731 times.
|
731 | if (mdl_request == nullptr) return true; |
| 9444 | |||
| 9445 |
1/2✓ Branch 0 taken 731 times.
✗ Branch 1 not taken.
|
731 | MDL_REQUEST_INIT(mdl_request, MDL_key::SCHEMA, schema_name, "", |
| 9446 | MDL_INTENTION_EXCLUSIVE, MDL_STATEMENT); | ||
| 9447 | |||
| 9448 |
1/2✓ Branch 0 taken 731 times.
✗ Branch 1 not taken.
|
731 | mdl_requests->push_front(mdl_request); |
| 9449 |
1/2✓ Branch 0 taken 731 times.
✗ Branch 1 not taken.
|
731 | } |
| 9450 | 115007 | return false; | |
| 9451 | 115007 | } | |
| 9452 | |||
| 9453 | 177219 | static bool reload_fk_parents_for_single_table(THD *thd, const char *db, | |
| 9454 | const char *name) { | ||
| 9455 | 177219 | dd::Table *table = nullptr; | |
| 9456 |
4/8✓ Branch 0 taken 177219 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 177219 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 177219 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 177219 times.
|
177219 | if (thd->dd_client()->acquire_for_modification(db, name, &table)) return true; |
| 9457 | |||
| 9458 | // Missing parent is allowed for tables created with F_K_C = 0. | ||
| 9459 |
2/2✓ Branch 0 taken 1019 times.
✓ Branch 1 taken 176200 times.
|
177219 | if (table == nullptr) return false; |
| 9460 | |||
| 9461 |
1/2✓ Branch 0 taken 176200 times.
✗ Branch 1 not taken.
|
176200 | bool before_image_empty = table->foreign_key_parents().empty(); |
| 9462 | |||
| 9463 | // Read uncommitted from the DD tables to reload the information. | ||
| 9464 |
2/4✓ Branch 0 taken 176200 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 176200 times.
|
176200 | if (table->reload_foreign_key_parents(thd)) return true; |
| 9465 | |||
| 9466 |
1/2✓ Branch 0 taken 176200 times.
✗ Branch 1 not taken.
|
176200 | bool after_image_empty = table->foreign_key_parents().empty(); |
| 9467 | |||
| 9468 | /* | ||
| 9469 | The changes are reflected in the uncommitted registry in the | ||
| 9470 | dictionary client, which is removed upon rollback. Upon commit, | ||
| 9471 | the corresponding object in the shared cache is invalidated. This | ||
| 9472 | means that there will be an update of the DD tables which is not | ||
| 9473 | necessary, and which also interferes with the use of the | ||
| 9474 | Foreign_key_parents_invalidator. | ||
| 9475 | |||
| 9476 | TODO: In the long term, extend the Dictionary_client to support | ||
| 9477 | caching changes that should not (or will not) be reflected | ||
| 9478 | in the DD tables. | ||
| 9479 | |||
| 9480 | TODO: In the short term, we can improve this to avoid unnecessary | ||
| 9481 | updates if the FK parent collection is unchanged. For now, | ||
| 9482 | skip update if the collection is empty both before and after | ||
| 9483 | reload. | ||
| 9484 | */ | ||
| 9485 |
4/4✓ Branch 0 taken 173767 times.
✓ Branch 1 taken 2433 times.
✓ Branch 2 taken 171988 times.
✓ Branch 3 taken 1779 times.
|
176200 | if (before_image_empty && after_image_empty) return false; |
| 9486 | |||
| 9487 |
1/2✓ Branch 0 taken 4212 times.
✗ Branch 1 not taken.
|
4212 | return thd->dd_client()->update(table); |
| 9488 | } | ||
| 9489 | |||
| 9490 | 306290 | bool adjust_fk_parents(THD *thd, const char *db, const char *name, | |
| 9491 | bool reload_self, | ||
| 9492 | const Foreign_key_parents_invalidator *fk_invalidator) { | ||
| 9493 | /* | ||
| 9494 | Can't reload self in case of e.g. DROP. Otherwise, reload the | ||
| 9495 | foreign key parents info in case we e.g. un-orphaned a child. | ||
| 9496 | */ | ||
| 9497 |
5/8✓ Branch 0 taken 172599 times.
✓ Branch 1 taken 133691 times.
✓ Branch 2 taken 172599 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 172599 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 306290 times.
|
306290 | if (reload_self && reload_fk_parents_for_single_table(thd, db, name)) |
| 9498 | ✗ | return true; | |
| 9499 | |||
| 9500 | /* | ||
| 9501 | If an invalidator is submitted, use it to decide which tables should | ||
| 9502 | have their FK parent info reloaded. This must be done e.g. for ALTER, | ||
| 9503 | since e.g. the dropped FKs will not be present in the table's FK list | ||
| 9504 | at this point. | ||
| 9505 | */ | ||
| 9506 |
2/2✓ Branch 0 taken 60255 times.
✓ Branch 1 taken 246035 times.
|
306290 | if (fk_invalidator != nullptr) { |
| 9507 |
3/4✓ Branch 0 taken 224 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 224 times.
✓ Branch 3 taken 60255 times.
|
60479 | for (auto parent : fk_invalidator->parents()) { |
| 9508 | // Self referencing keys should be updated above if reload_self == true. | ||
| 9509 |
1/2✓ Branch 0 taken 224 times.
✗ Branch 1 not taken.
|
224 | if ((my_strcasecmp(table_alias_charset, parent.first.first.c_str(), db) != |
| 9510 | 218 | 0 || | |
| 9511 |
2/4✓ Branch 0 taken 218 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 218 times.
✗ Branch 3 not taken.
|
218 | my_strcasecmp(table_alias_charset, parent.first.second.c_str(), |
| 9512 |
3/4✓ Branch 0 taken 218 times.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 224 times.
|
448 | name) != 0) && |
| 9513 |
2/4✓ Branch 0 taken 224 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 224 times.
|
224 | reload_fk_parents_for_single_table(thd, parent.first.first.c_str(), |
| 9514 | parent.first.second.c_str())) | ||
| 9515 | ✗ | return true; | |
| 9516 |
1/2✓ Branch 0 taken 224 times.
✗ Branch 1 not taken.
|
224 | } |
| 9517 | 60255 | return false; | |
| 9518 | } | ||
| 9519 | |||
| 9520 | /* | ||
| 9521 | Otherwise, use the FK list in the table and reload FK parent info | ||
| 9522 | for each parent. | ||
| 9523 | */ | ||
| 9524 | 246035 | const dd::Table *table = nullptr; | |
| 9525 |
4/8✓ Branch 0 taken 246035 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 246035 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 246035 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 246035 times.
|
246035 | if (thd->dd_client()->acquire(db, name, &table)) return true; |
| 9526 | |||
| 9527 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 246035 times.
|
246035 | assert(table); |
| 9528 | |||
| 9529 |
6/10✓ Branch 0 taken 246035 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 246035 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 246035 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4506 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4506 times.
✓ Branch 9 taken 246035 times.
|
250541 | for (const dd::Foreign_key *fk : table->foreign_keys()) { |
| 9530 | // Self referencing keys should be updated above if reload_self == true. | ||
| 9531 |
2/4✓ Branch 0 taken 4506 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4506 times.
✗ Branch 3 not taken.
|
4506 | if ((my_strcasecmp(table_alias_charset, |
| 9532 | 4482 | fk->referenced_table_schema_name().c_str(), db) != 0 || | |
| 9533 |
4/6✓ Branch 0 taken 4482 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4482 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4372 times.
✓ Branch 5 taken 110 times.
|
4482 | my_strcasecmp(table_alias_charset, fk->referenced_table_name().c_str(), |
| 9534 |
3/4✓ Branch 0 taken 4482 times.
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4506 times.
|
9012 | name) != 0) && |
| 9535 |
2/4✓ Branch 0 taken 4396 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4396 times.
|
4396 | reload_fk_parents_for_single_table( |
| 9536 |
1/2✓ Branch 0 taken 4396 times.
✗ Branch 1 not taken.
|
4396 | thd, fk->referenced_table_schema_name().c_str(), |
| 9537 |
1/2✓ Branch 0 taken 4396 times.
✗ Branch 1 not taken.
|
4396 | fk->referenced_table_name().c_str())) |
| 9538 | ✗ | return true; | |
| 9539 | } | ||
| 9540 | 246035 | return false; | |
| 9541 | } | ||
| 9542 | |||
| 9543 | /** | ||
| 9544 | Check if foreign key's parent table has a column compatible with foreign key's | ||
| 9545 | referenced column. | ||
| 9546 | |||
| 9547 | @param[in] parent_table_def Data-dictionary object for parent table. | ||
| 9548 | @param[in] fk Data-dictionary object for foreign key. | ||
| 9549 | @param[in] fk_el Data-dictionary object for foreign key | ||
| 9550 | element. | ||
| 9551 | @param[in] hton Handlerton for table's storage engine. | ||
| 9552 | |||
| 9553 | @retval false Success. | ||
| 9554 | @retval true Failure. | ||
| 9555 | */ | ||
| 9556 | 979 | static bool check_table_has_col_compatible_with_fk_ref_col( | |
| 9557 | const dd::Table *parent_table_def, const dd::Foreign_key *fk, | ||
| 9558 | const dd::Foreign_key_element *fk_el, handlerton *hton) { | ||
| 9559 | 1041 | auto same_column_name = [fk_el](const dd::Column *c) { | |
| 9560 | 1041 | return my_strcasecmp(system_charset_info, c->name().c_str(), | |
| 9561 | 1041 | fk_el->referenced_column_name().c_str()) == 0; | |
| 9562 | 979 | }; | |
| 9563 | auto ref_column = | ||
| 9564 |
3/6✓ Branch 0 taken 979 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 979 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 979 times.
✗ Branch 5 not taken.
|
979 | std::find_if(parent_table_def->columns().begin(), |
| 9565 |
2/4✓ Branch 0 taken 979 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 979 times.
✗ Branch 3 not taken.
|
979 | parent_table_def->columns().end(), same_column_name); |
| 9566 |
4/6✓ Branch 0 taken 979 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 979 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 978 times.
|
979 | if (ref_column == parent_table_def->columns().end()) { |
| 9567 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_FK_NO_COLUMN_PARENT, MYF(0), |
| 9568 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | fk_el->referenced_column_name().c_str(), fk->name().c_str(), |
| 9569 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | fk->referenced_table_name().c_str()); |
| 9570 | 1 | return true; | |
| 9571 | } | ||
| 9572 | |||
| 9573 |
3/6✓ Branch 0 taken 978 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 978 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 978 times.
|
978 | if ((*ref_column)->is_virtual()) { |
| 9574 | ✗ | my_error(ER_FK_CANNOT_USE_VIRTUAL_COLUMN, MYF(0), fk->name().c_str(), | |
| 9575 | ✗ | fk_el->referenced_column_name().c_str()); | |
| 9576 | ✗ | return true; | |
| 9577 | } | ||
| 9578 | |||
| 9579 | // Check that type of referencing and referenced columns are compatible. | ||
| 9580 |
1/2✓ Branch 0 taken 978 times.
✗ Branch 1 not taken.
|
978 | if (hton->check_fk_column_compat) { |
| 9581 | Ha_fk_column_type child_column_type, parent_column_type; | ||
| 9582 | |||
| 9583 |
4/8✓ Branch 0 taken 978 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 978 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 978 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 978 times.
|
1956 | if (fill_ha_fk_column_type(&child_column_type, &fk_el->column()) || |
| 9584 |
3/6✓ Branch 0 taken 978 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 978 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 978 times.
|
978 | fill_ha_fk_column_type(&parent_column_type, *ref_column)) |
| 9585 | 9 | return true; | |
| 9586 | |||
| 9587 |
3/4✓ Branch 0 taken 978 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 969 times.
|
978 | if (!hton->check_fk_column_compat(&child_column_type, &parent_column_type, |
| 9588 | true)) { | ||
| 9589 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
9 | my_error(ER_FK_INCOMPATIBLE_COLUMNS, MYF(0), |
| 9590 |
2/4✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
|
9 | fk_el->column().name().c_str(), |
| 9591 |
2/4✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
|
9 | fk_el->referenced_column_name().c_str(), fk->name().c_str()); |
| 9592 | 9 | return true; | |
| 9593 | } | ||
| 9594 | } | ||
| 9595 | |||
| 9596 | 969 | return false; | |
| 9597 | } | ||
| 9598 | |||
| 9599 | /** | ||
| 9600 | Check if new definition of parent table is compatible with foreign keys | ||
| 9601 | on child table which reference it. Update the unique constraint names and | ||
| 9602 | referenced column names for the foreign keys accordingly. | ||
| 9603 | |||
| 9604 | @param thd Thread handle. | ||
| 9605 | @param check_only Indicates that we only need to check parent key | ||
| 9606 | existence and do not do real update. | ||
| 9607 | @param check_charsets Indicates whether we need to check charsets of | ||
| 9608 | columns participating in foreign keys. | ||
| 9609 | @param child_table_db Child table schema name. | ||
| 9610 | @param child_table_name Child table name. | ||
| 9611 | @param parent_table_db Parent table schema name. | ||
| 9612 | @param parent_table_name Parent table name. | ||
| 9613 | @param hton Handlerton for tables' storage engine. | ||
| 9614 | @param parent_table_def Table object representing the new version of | ||
| 9615 | referenced table. | ||
| 9616 | @param parent_alter_info Alter_info containing information about renames | ||
| 9617 | of parent columns. Can be nullptr if there are | ||
| 9618 | no such renames. | ||
| 9619 | @param old_parent_table_def Table object representing the old version of | ||
| 9620 | referenced table. Can be nullptr if this is | ||
| 9621 | not ALTER TABLE. Used for error reporting. | ||
| 9622 | |||
| 9623 | @retval operation outcome, false if no error. | ||
| 9624 | */ | ||
| 9625 | 1126 | static bool adjust_fk_child_after_parent_def_change( | |
| 9626 | THD *thd, bool check_only, bool check_charsets, const char *child_table_db, | ||
| 9627 | const char *child_table_name, const char *parent_table_db, | ||
| 9628 | const char *parent_table_name, handlerton *hton, | ||
| 9629 | const dd::Table *parent_table_def, Alter_info *parent_alter_info, | ||
| 9630 | const dd::Table *old_parent_table_def) { | ||
| 9631 |
1/2✓ Branch 0 taken 1126 times.
✗ Branch 1 not taken.
|
1126 | dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client()); |
| 9632 | |||
| 9633 | 1126 | dd::Table *child_table_def = nullptr; | |
| 9634 | 1126 | const dd::Table *old_child_table_def = nullptr; | |
| 9635 | |||
| 9636 |
4/8✓ Branch 0 taken 1126 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1126 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1126 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1126 times.
|
1126 | if (thd->dd_client()->acquire_for_modification( |
| 9637 | child_table_db, child_table_name, &child_table_def)) | ||
| 9638 | ✗ | return true; | |
| 9639 | |||
| 9640 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1126 times.
|
1126 | if (child_table_def == nullptr) { |
| 9641 | // Safety. | ||
| 9642 | ✗ | return false; | |
| 9643 | } | ||
| 9644 | |||
| 9645 | /* | ||
| 9646 | Check if we are making parent table in a foreign key (possibly | ||
| 9647 | previously orphan) a partitioned table and table's storage engine | ||
| 9648 | doesn't support foreign keys over partitioned tables. | ||
| 9649 | */ | ||
| 9650 |
5/6✓ Branch 0 taken 1126 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1125 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1125 times.
|
1127 | if (parent_table_def->partition_type() != dd::Table::PT_NONE && |
| 9651 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | (!hton->partition_flags || |
| 9652 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | hton->partition_flags() & HA_CANNOT_PARTITION_FK)) { |
| 9653 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_FOREIGN_KEY_ON_PARTITIONED, MYF(0)); |
| 9654 | 1 | return true; | |
| 9655 | } | ||
| 9656 | |||
| 9657 |
2/2✓ Branch 0 taken 100 times.
✓ Branch 1 taken 1025 times.
|
1225 | if (old_parent_table_def != nullptr && |
| 9658 |
9/18✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 100 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 100 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 100 times.
✓ Branch 8 taken 100 times.
✓ Branch 9 taken 1025 times.
✓ Branch 10 taken 100 times.
✓ Branch 11 taken 1025 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 1125 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
|
1225 | thd->dd_client()->acquire(child_table_db, child_table_name, |
| 9659 | &old_child_table_def)) | ||
| 9660 | ✗ | return true; | |
| 9661 | |||
| 9662 |
3/4✓ Branch 0 taken 100 times.
✓ Branch 1 taken 1025 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 100 times.
|
1125 | assert(old_parent_table_def == nullptr || old_child_table_def != nullptr); |
| 9663 | |||
| 9664 |
6/10✓ Branch 0 taken 1125 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1125 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1125 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2414 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2414 times.
✓ Branch 9 taken 1103 times.
|
3517 | for (dd::Foreign_key *fk : *(child_table_def->foreign_keys())) { |
| 9665 |
2/4✓ Branch 0 taken 2414 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2414 times.
✗ Branch 3 not taken.
|
2414 | if (my_strcasecmp(table_alias_charset, |
| 9666 | fk->referenced_table_schema_name().c_str(), | ||
| 9667 |
3/4✓ Branch 0 taken 2414 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1127 times.
✓ Branch 3 taken 1287 times.
|
4828 | parent_table_db) == 0 && |
| 9668 |
4/6✓ Branch 0 taken 2414 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2414 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1127 times.
✓ Branch 5 taken 1287 times.
|
2414 | my_strcasecmp(table_alias_charset, fk->referenced_table_name().c_str(), |
| 9669 | parent_table_name) == 0) { | ||
| 9670 |
6/10✓ Branch 0 taken 1127 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1127 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1127 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1167 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1167 times.
✓ Branch 9 taken 1113 times.
|
2280 | for (dd::Foreign_key_element *fk_el : *(fk->elements())) { |
| 9671 |
2/2✓ Branch 0 taken 190 times.
✓ Branch 1 taken 977 times.
|
1167 | if (parent_alter_info) { |
| 9672 | /* | ||
| 9673 | The parent table is ALTERed. Check that referenced column was | ||
| 9674 | not dropped and update foreign key definition with its new | ||
| 9675 | name if it was renamed. The latter needs to be done before | ||
| 9676 | searching for parent key. | ||
| 9677 | */ | ||
| 9678 |
1/2✓ Branch 0 taken 190 times.
✗ Branch 1 not taken.
|
190 | List_iterator<Create_field> find_it(parent_alter_info->create_list); |
| 9679 | const Create_field *find; | ||
| 9680 | |||
| 9681 |
2/2✓ Branch 0 taken 102 times.
✓ Branch 1 taken 88 times.
|
190 | if (check_only) { |
| 9682 | /* | ||
| 9683 | This is early stage of ALTER TABLE, so Alter_info::create_list is | ||
| 9684 | fully available and we can use it both to check that column exists | ||
| 9685 | and to handle column renames. | ||
| 9686 | */ | ||
| 9687 |
2/2✓ Branch 0 taken 137 times.
✓ Branch 1 taken 2 times.
|
139 | while ((find = find_it++)) { |
| 9688 |
3/4✓ Branch 0 taken 137 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 100 times.
✓ Branch 3 taken 37 times.
|
274 | if (find->field && |
| 9689 |
4/6✓ Branch 0 taken 137 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 137 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 100 times.
✓ Branch 5 taken 37 times.
|
137 | my_strcasecmp(system_charset_info, |
| 9690 | fk_el->referenced_column_name().c_str(), | ||
| 9691 | find->field->field_name) == 0) { | ||
| 9692 | 100 | break; | |
| 9693 | } | ||
| 9694 | } | ||
| 9695 | |||
| 9696 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 100 times.
|
102 | if (find == nullptr) { |
| 9697 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | my_error(ER_FK_COLUMN_CANNOT_DROP_CHILD, MYF(0), |
| 9698 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | fk_el->referenced_column_name().c_str(), |
| 9699 |
3/6✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
2 | fk->name().c_str(), fk->table().name().c_str()); |
| 9700 | 4 | return true; | |
| 9701 | } | ||
| 9702 | |||
| 9703 | /* | ||
| 9704 | Column can't be made virtual as we don't allow ALTERs which make | ||
| 9705 | stored columns virtual. | ||
| 9706 | */ | ||
| 9707 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 100 times.
|
100 | assert(!find->is_virtual_gcol()); |
| 9708 | |||
| 9709 | // Use new column name in foreign key definition if name was | ||
| 9710 | // changed. | ||
| 9711 |
2/2✓ Branch 0 taken 26 times.
✓ Branch 1 taken 74 times.
|
100 | if (find->change != nullptr) { |
| 9712 |
2/4✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
|
26 | fk_el->referenced_column_name(find->field_name); |
| 9713 | } | ||
| 9714 | |||
| 9715 | /* | ||
| 9716 | Check that types of child and parent columns are compatible. | ||
| 9717 | */ | ||
| 9718 |
1/2✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
|
100 | if (hton->check_fk_column_compat) { |
| 9719 | Ha_fk_column_type child_column_type, parent_column_type; | ||
| 9720 | |||
| 9721 |
3/6✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 100 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 100 times.
|
100 | if (fill_ha_fk_column_type(&child_column_type, &fk_el->column())) |
| 9722 | 2 | return true; | |
| 9723 |
1/2✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
|
100 | fill_ha_fk_column_type(&parent_column_type, find); |
| 9724 | |||
| 9725 |
3/4✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 98 times.
|
100 | if (!hton->check_fk_column_compat(&child_column_type, |
| 9726 | &parent_column_type, | ||
| 9727 | check_charsets)) { | ||
| 9728 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | my_error(ER_FK_INCOMPATIBLE_COLUMNS, MYF(0), |
| 9729 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | fk_el->column().name().c_str(), |
| 9730 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | fk_el->referenced_column_name().c_str(), |
| 9731 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | fk->name().c_str()); |
| 9732 | 2 | return true; | |
| 9733 | } | ||
| 9734 | } | ||
| 9735 | } else { | ||
| 9736 | /* | ||
| 9737 | This is late stage of ALTER TABLE. Some elements in | ||
| 9738 | Alter_info::create_list are not fully valid. However, | ||
| 9739 | those which are related to renaming of columns are, | ||
| 9740 | so we can use them to update foreign key definitions. | ||
| 9741 | Luckily, thanks to check at early stage of ALTER TABLE | ||
| 9742 | we don't need to do anything else here. | ||
| 9743 | */ | ||
| 9744 |
2/2✓ Branch 0 taken 279 times.
✓ Branch 1 taken 65 times.
|
344 | while ((find = find_it++)) { |
| 9745 |
4/4✓ Branch 0 taken 26 times.
✓ Branch 1 taken 253 times.
✓ Branch 2 taken 23 times.
✓ Branch 3 taken 256 times.
|
305 | if (find->change && |
| 9746 |
4/6✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
✓ Branch 5 taken 3 times.
|
26 | my_strcasecmp(system_charset_info, |
| 9747 | fk_el->referenced_column_name().c_str(), | ||
| 9748 | find->change) == 0) { | ||
| 9749 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | fk_el->referenced_column_name(find->field_name); |
| 9750 | 23 | break; | |
| 9751 | } | ||
| 9752 | } | ||
| 9753 | } | ||
| 9754 | } else { | ||
| 9755 | /* | ||
| 9756 | We add parent table for previously orphan foreign key by doing | ||
| 9757 | CREATE or RENAME TABLE. We need to check that it has columns | ||
| 9758 | which match referenced columns in foreign key. | ||
| 9759 | */ | ||
| 9760 |
3/4✓ Branch 0 taken 977 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 967 times.
|
977 | if (check_table_has_col_compatible_with_fk_ref_col(parent_table_def, |
| 9761 | fk, fk_el, hton)) | ||
| 9762 | 10 | return true; | |
| 9763 | } | ||
| 9764 | } | ||
| 9765 | |||
| 9766 | /* | ||
| 9767 | This function is never, and should never be, called for self referencing | ||
| 9768 | foreign keys. Hence, we can submit 'false' for 'is_self_referenceing_fk' | ||
| 9769 | in the call to prepare_fk_parent_key(). | ||
| 9770 | */ | ||
| 9771 |
6/12✓ Branch 0 taken 1113 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1113 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1113 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1113 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1113 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 1113 times.
|
1113 | assert(my_strcasecmp(table_alias_charset, |
| 9772 | fk->referenced_table_schema_name().c_str(), | ||
| 9773 | child_table_db) || | ||
| 9774 | my_strcasecmp(table_alias_charset, | ||
| 9775 | fk->referenced_table_name().c_str(), | ||
| 9776 | child_table_name)); | ||
| 9777 | |||
| 9778 |
3/4✓ Branch 0 taken 1113 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 1105 times.
|
1113 | if (prepare_fk_parent_key(hton, parent_table_def, old_parent_table_def, |
| 9779 | old_child_table_def, false, fk)) | ||
| 9780 | 8 | return true; | |
| 9781 | } | ||
| 9782 | } | ||
| 9783 | |||
| 9784 |
5/8✓ Branch 0 taken 1009 times.
✓ Branch 1 taken 94 times.
✓ Branch 2 taken 1009 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1009 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1103 times.
|
1103 | if (!check_only && thd->dd_client()->update(child_table_def)) return true; |
| 9785 | |||
| 9786 | 1103 | return false; | |
| 9787 | 1126 | } | |
| 9788 | |||
| 9789 | 172871 | bool adjust_fk_children_after_parent_def_change( | |
| 9790 | THD *thd, bool check_charsets, const char *parent_table_db, | ||
| 9791 | const char *parent_table_name, handlerton *hton, | ||
| 9792 | const dd::Table *parent_table_def, Alter_info *parent_alter_info, | ||
| 9793 | bool invalidate_tdc) { | ||
| 9794 | 172871 | Normalized_fk_children fk_children; | |
| 9795 |
3/6✓ Branch 0 taken 172871 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 172871 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 172871 times.
|
172871 | if (fetch_fk_children_uncached_uncommitted_normalized( |
| 9796 | thd, parent_table_db, parent_table_name, | ||
| 9797 | ha_resolve_storage_engine_name(hton), &fk_children)) | ||
| 9798 | ✗ | return true; | |
| 9799 | |||
| 9800 |
3/4✓ Branch 0 taken 1104 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1104 times.
✓ Branch 3 taken 172864 times.
|
173968 | for (auto fk_children_it : fk_children) { |
| 9801 | 1104 | const char *schema_name = fk_children_it.first.c_str(); | |
| 9802 | 1104 | const char *table_name = fk_children_it.second.c_str(); | |
| 9803 | |||
| 9804 |
4/6✓ Branch 0 taken 1104 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1104 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 88 times.
✓ Branch 5 taken 1016 times.
|
2208 | if (my_strcasecmp(table_alias_charset, schema_name, parent_table_db) == 0 && |
| 9805 |
3/4✓ Branch 0 taken 1104 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 88 times.
✓ Branch 3 taken 1016 times.
|
1104 | my_strcasecmp(table_alias_charset, table_name, parent_table_name) == |
| 9806 | 0) { | ||
| 9807 | // Safety. Self-referencing foreign keys are handled earlier. | ||
| 9808 | 88 | continue; | |
| 9809 | } | ||
| 9810 | |||
| 9811 | /* | ||
| 9812 | Since we always pass nullptr as old parent table definition pointer | ||
| 9813 | to the below call, the error message reported by it might be not the | ||
| 9814 | best one for the case when we call this function for ALTER TABLE | ||
| 9815 | which drops parent key. But this does not matter as such errors | ||
| 9816 | should have been normally detected and reported by earlier call | ||
| 9817 | to check_fk_children_after_parent_def_change(). | ||
| 9818 | */ | ||
| 9819 |
3/4✓ Branch 0 taken 1016 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 1009 times.
|
1016 | if (adjust_fk_child_after_parent_def_change( |
| 9820 | thd, false /* Update FKs. */, check_charsets, schema_name, | ||
| 9821 | table_name, parent_table_db, parent_table_name, hton, | ||
| 9822 | parent_table_def, parent_alter_info, nullptr)) | ||
| 9823 | 7 | return true; | |
| 9824 | |||
| 9825 |
2/2✓ Branch 0 taken 793 times.
✓ Branch 1 taken 216 times.
|
1009 | if (invalidate_tdc) { |
| 9826 |
1/2✓ Branch 0 taken 793 times.
✗ Branch 1 not taken.
|
793 | mysql_ha_flush_table(thd, schema_name, table_name); |
| 9827 |
1/2✓ Branch 0 taken 793 times.
✗ Branch 1 not taken.
|
793 | close_all_tables_for_name(thd, schema_name, table_name, false); |
| 9828 | } | ||
| 9829 | |||
| 9830 | #ifdef DISABLED_UNTIL_WL9533 | ||
| 9831 | /* | ||
| 9832 | TODO: Simply removing entries from InnoDB internal cache breaks | ||
| 9833 | its FK checking logic at the moment. This is to be solved | ||
| 9834 | as part of WL#9533. We might have to replace invalidation | ||
| 9835 | with cache update to do this.Also we might have to postpone | ||
| 9836 | such invalidation/update until statement commit time. | ||
| 9837 | */ | ||
| 9838 | if (hton->dict_cache_reset) hton->dict_cache_reset(schema_name, table_name); | ||
| 9839 | #endif | ||
| 9840 |
3/3✓ Branch 0 taken 1009 times.
✓ Branch 1 taken 88 times.
✓ Branch 2 taken 7 times.
|
1104 | } |
| 9841 | |||
| 9842 | 172864 | return false; | |
| 9843 | 172871 | } | |
| 9844 | |||
| 9845 | /** | ||
| 9846 | Check if new definition of parent table is compatible with foreign keys which | ||
| 9847 | reference it. | ||
| 9848 | |||
| 9849 | @param thd Thread handle. | ||
| 9850 | @param parent_table_db Parent table schema name. | ||
| 9851 | @param parent_table_name Parent table name. | ||
| 9852 | @param hton Handlerton for tables' storage engine. | ||
| 9853 | @param old_parent_table_def Table object representing the old version of | ||
| 9854 | parent table. | ||
| 9855 | @param new_parent_table_def Table object representing the new version of | ||
| 9856 | parent table. | ||
| 9857 | @param parent_alter_info Alter_info containing information about renames | ||
| 9858 | of parent columns. | ||
| 9859 | |||
| 9860 | @retval operation outcome, false if no error. | ||
| 9861 | */ | ||
| 9862 | 77062 | static bool check_fk_children_after_parent_def_change( | |
| 9863 | THD *thd, const char *parent_table_db, const char *parent_table_name, | ||
| 9864 | handlerton *hton, const dd::Table *old_parent_table_def, | ||
| 9865 | const dd::Table *new_parent_table_def, Alter_info *parent_alter_info) { | ||
| 9866 | 77062 | for (const dd::Foreign_key_parent *parent_fk : | |
| 9867 |
3/4✓ Branch 0 taken 77062 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 102 times.
✓ Branch 3 taken 77052 times.
|
154216 | old_parent_table_def->foreign_key_parents()) { |
| 9868 | // Self-referencing FKs are handled separately. | ||
| 9869 |
1/2✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
|
102 | if (my_strcasecmp(table_alias_charset, |
| 9870 | parent_fk->child_schema_name().c_str(), | ||
| 9871 |
3/4✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 101 times.
|
204 | parent_table_db) == 0 && |
| 9872 |
3/4✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 101 times.
|
102 | my_strcasecmp(table_alias_charset, |
| 9873 | parent_fk->child_table_name().c_str(), | ||
| 9874 | parent_table_name) == 0) | ||
| 9875 | 1 | continue; | |
| 9876 | |||
| 9877 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 91 times.
|
303 | if (adjust_fk_child_after_parent_def_change( |
| 9878 | thd, true, // Check only. | ||
| 9879 | /* | ||
| 9880 | Allow charset discrepancies between child and parent columns | ||
| 9881 | in FOREIGN_KEY_CHECKS=0 mode. This provides a way to change | ||
| 9882 | charset of column which participates in a foreign key without | ||
| 9883 | dropping the latter (Note that in general case there is no way | ||
| 9884 | to change charset of both child and parent columns | ||
| 9885 | simultaneously). | ||
| 9886 | We do not allow creation of same discrepancies when adding | ||
| 9887 | new foreign key using CREATE/ALTER TABLE or adding new parent | ||
| 9888 | for existing orphan foreign key using CREATE/RENAME TABLE. | ||
| 9889 | */ | ||
| 9890 |
1/2✓ Branch 0 taken 101 times.
✗ Branch 1 not taken.
|
101 | !(thd->variables.option_bits & OPTION_NO_FOREIGN_KEY_CHECKS), |
| 9891 | 101 | parent_fk->child_schema_name().c_str(), | |
| 9892 | 101 | parent_fk->child_table_name().c_str(), parent_table_db, | |
| 9893 | parent_table_name, hton, new_parent_table_def, parent_alter_info, | ||
| 9894 | old_parent_table_def)) | ||
| 9895 | 10 | return true; | |
| 9896 | } | ||
| 9897 | |||
| 9898 | 77052 | return false; | |
| 9899 | } | ||
| 9900 | |||
| 9901 | /** | ||
| 9902 | Check if new definition of parent table is compatible with foreign keys which | ||
| 9903 | reference it and were previously orphan. | ||
| 9904 | |||
| 9905 | @param thd Thread handle. | ||
| 9906 | @param parent_table_db Parent table schema name. | ||
| 9907 | @param parent_table_name Parent table name. | ||
| 9908 | @param old_parent_table_db Old parent table schema name, if table is | ||
| 9909 | renamed. | ||
| 9910 | @param old_parent_table_name Old parent table name, if table is renamed. | ||
| 9911 | @param hton Handlerton for table's storage engine. | ||
| 9912 | @param parent_table_def Table object representing the parent table. | ||
| 9913 | |||
| 9914 | @retval operation outcome, false if no error. | ||
| 9915 | */ | ||
| 9916 | 1093 | static bool check_fk_children_after_parent_def_change( | |
| 9917 | THD *thd, const char *parent_table_db, const char *parent_table_name, | ||
| 9918 | const char *old_parent_table_db, const char *old_parent_table_name, | ||
| 9919 | handlerton *hton, const dd::Table *parent_table_def) { | ||
| 9920 | 1093 | Normalized_fk_children fk_children; | |
| 9921 |
3/6✓ Branch 0 taken 1093 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1093 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1093 times.
|
1093 | if (fetch_fk_children_uncached_uncommitted_normalized( |
| 9922 | thd, parent_table_db, parent_table_name, | ||
| 9923 | ha_resolve_storage_engine_name(hton), &fk_children)) | ||
| 9924 | ✗ | return true; | |
| 9925 | |||
| 9926 |
3/4✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 1087 times.
|
1096 | for (auto fk_children_it : fk_children) { |
| 9927 | 9 | const char *schema_name = fk_children_it.first.c_str(); | |
| 9928 | 9 | const char *table_name = fk_children_it.second.c_str(); | |
| 9929 | |||
| 9930 |
3/6✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 9 times.
|
18 | if (my_strcasecmp(table_alias_charset, schema_name, parent_table_db) == 0 && |
| 9931 |
2/4✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
|
9 | my_strcasecmp(table_alias_charset, table_name, parent_table_name) == |
| 9932 | 0) { | ||
| 9933 | // Safety. Self-referencing FKs are handled separately. | ||
| 9934 | ✗ | continue; | |
| 9935 | } | ||
| 9936 | |||
| 9937 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 7 times.
|
9 | if (old_parent_table_name != nullptr) { |
| 9938 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | assert(old_parent_table_db != nullptr); |
| 9939 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (my_strcasecmp(table_alias_charset, schema_name, |
| 9940 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
4 | old_parent_table_db) == 0 && |
| 9941 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
2 | my_strcasecmp(table_alias_charset, table_name, |
| 9942 | old_parent_table_name) == 0) { | ||
| 9943 | /* | ||
| 9944 | In case of ALTER TABLE with RENAME clause, the above check involving | ||
| 9945 | parent_table_db and parent_table_name will skip orphan FKs which | ||
| 9946 | will become non-orphan/adopted self-referencing FKs as result of this | ||
| 9947 | RENAME. Hence we need to do additional check using old_parent_table_db | ||
| 9948 | and old_parent_table_name for non-orphan/adopted self-referencing FKs. | ||
| 9949 | */ | ||
| 9950 | ✗ | continue; | |
| 9951 | } | ||
| 9952 | } | ||
| 9953 | |||
| 9954 |
3/4✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 3 times.
|
9 | if (adjust_fk_child_after_parent_def_change( |
| 9955 | thd, true, // Check only. | ||
| 9956 | true, // Check that charsets match. | ||
| 9957 | schema_name, table_name, parent_table_db, parent_table_name, hton, | ||
| 9958 | parent_table_def, nullptr, nullptr)) | ||
| 9959 | 6 | return true; | |
| 9960 |
2/3✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
|
9 | } |
| 9961 | 1087 | return false; | |
| 9962 | 1093 | } | |
| 9963 | |||
| 9964 | /** | ||
| 9965 | Update the referenced schema- and/or table name for the referencing tables | ||
| 9966 | when the referenced table is renamed. | ||
| 9967 | |||
| 9968 | @param thd Thread handle. | ||
| 9969 | @param parent_table_db Old schema name. | ||
| 9970 | @param parent_table_name Old table name. | ||
| 9971 | @param hton Handlerton for table's storage engine. | ||
| 9972 | @param new_db New schema name. | ||
| 9973 | @param new_table_name New table name. | ||
| 9974 | |||
| 9975 | @retval operation outcome, false if no error. | ||
| 9976 | */ | ||
| 9977 | 2036 | static bool adjust_fk_children_after_parent_rename( | |
| 9978 | THD *thd, const char *parent_table_db, const char *parent_table_name, | ||
| 9979 | handlerton *hton, const char *new_db, const char *new_table_name) { | ||
| 9980 | 2036 | Normalized_fk_children fk_children; | |
| 9981 |
3/6✓ Branch 0 taken 2036 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2036 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2036 times.
|
2036 | if (fetch_fk_children_uncached_uncommitted_normalized( |
| 9982 | thd, parent_table_db, parent_table_name, | ||
| 9983 | ha_resolve_storage_engine_name(hton), &fk_children)) | ||
| 9984 | ✗ | return true; | |
| 9985 | |||
| 9986 |
3/4✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 2036 times.
|
2047 | for (auto fk_children_it : fk_children) { |
| 9987 | 11 | const char *schema_name = fk_children_it.first.c_str(); | |
| 9988 | 11 | const char *table_name = fk_children_it.second.c_str(); | |
| 9989 | |||
| 9990 |
3/6✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 11 times.
|
22 | if (my_strcasecmp(table_alias_charset, schema_name, parent_table_db) == 0 && |
| 9991 |
2/4✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
|
11 | my_strcasecmp(table_alias_charset, table_name, parent_table_name) == |
| 9992 | 0) { | ||
| 9993 | ✗ | continue; | |
| 9994 | } | ||
| 9995 | |||
| 9996 | 11 | dd::Table *child_table_def = nullptr; | |
| 9997 | |||
| 9998 |
4/8✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 11 times.
|
11 | if (thd->dd_client()->acquire_for_modification(schema_name, table_name, |
| 9999 | &child_table_def)) | ||
| 10000 | ✗ | return true; | |
| 10001 | |||
| 10002 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
|
11 | assert(child_table_def != nullptr); |
| 10003 | |||
| 10004 |
6/10✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 17 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 17 times.
✓ Branch 9 taken 11 times.
|
28 | for (dd::Foreign_key *fk : *(child_table_def->foreign_keys())) { |
| 10005 |
2/4✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
|
17 | if (my_strcasecmp(table_alias_charset, |
| 10006 | fk->referenced_table_schema_name().c_str(), | ||
| 10007 |
3/4✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 6 times.
|
34 | parent_table_db) == 0 && |
| 10008 |
4/6✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11 times.
✓ Branch 5 taken 6 times.
|
17 | my_strcasecmp(table_alias_charset, |
| 10009 | fk->referenced_table_name().c_str(), | ||
| 10010 | parent_table_name) == 0) { | ||
| 10011 |
2/4✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
|
11 | fk->set_referenced_table_schema_name(new_db); |
| 10012 |
2/4✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
|
11 | fk->set_referenced_table_name(new_table_name); |
| 10013 | } | ||
| 10014 | } | ||
| 10015 | |||
| 10016 |
2/4✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
|
11 | if (thd->dd_client()->update(child_table_def)) return true; |
| 10017 | |||
| 10018 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
11 | mysql_ha_flush_table(thd, schema_name, table_name); |
| 10019 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
11 | close_all_tables_for_name(thd, schema_name, table_name, false); |
| 10020 | |||
| 10021 | #ifdef DISABLED_UNTIL_WL9533 | ||
| 10022 | /* | ||
| 10023 | TODO: Simply removing entries from InnoDB internal cache breaks | ||
| 10024 | its FK checking logic at the moment. This is to be solved | ||
| 10025 | as part of WL#9533. We might have to replace invalidation | ||
| 10026 | with cache update to do this.Also we might have to postpone | ||
| 10027 | such invalidation/update until statement commit time. | ||
| 10028 | */ | ||
| 10029 | if (hton->dict_cache_reset) hton->dict_cache_reset(schema_name, table_name); | ||
| 10030 | #endif | ||
| 10031 |
1/3✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
|
11 | } |
| 10032 | |||
| 10033 | 2036 | return false; | |
| 10034 | 2036 | } | |
| 10035 | |||
| 10036 | 706289 | bool collect_fk_parents_for_new_fks( | |
| 10037 | THD *thd, const char *db_name, const char *table_name, | ||
| 10038 | const Alter_info *alter_info, enum_mdl_type lock_type, handlerton *hton, | ||
| 10039 | MDL_request_list *mdl_requests, | ||
| 10040 | Foreign_key_parents_invalidator *fk_invalidator) { | ||
| 10041 |
2/2✓ Branch 0 taken 2618695 times.
✓ Branch 1 taken 706289 times.
|
3324984 | for (const Key_spec *key : alter_info->key_list) { |
| 10042 |
2/2✓ Branch 0 taken 613139 times.
✓ Branch 1 taken 2005556 times.
|
2618695 | if (key->type == KEYTYPE_FOREIGN) { |
| 10043 | 613139 | const Foreign_key_spec *fk = down_cast<const Foreign_key_spec *>(key); | |
| 10044 | |||
| 10045 |
4/4✓ Branch 0 taken 613112 times.
✓ Branch 1 taken 27 times.
✓ Branch 2 taken 12029 times.
✓ Branch 3 taken 601110 times.
|
1226251 | if (my_strcasecmp(table_alias_charset, fk->ref_db.str, db_name) == 0 && |
| 10046 |
2/2✓ Branch 0 taken 12029 times.
✓ Branch 1 taken 601083 times.
|
613112 | my_strcasecmp(table_alias_charset, fk->ref_table.str, table_name) == |
| 10047 | 0) | ||
| 10048 | 12029 | continue; | |
| 10049 | |||
| 10050 |
1/2✓ Branch 0 taken 601110 times.
✗ Branch 1 not taken.
|
601110 | MDL_request *mdl_request = new (thd->mem_root) MDL_request; |
| 10051 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 601110 times.
|
601110 | if (mdl_request == nullptr) return true; |
| 10052 | |||
| 10053 | 601110 | MDL_REQUEST_INIT(mdl_request, MDL_key::TABLE, fk->ref_db.str, | |
| 10054 | fk->ref_table.str, lock_type, MDL_STATEMENT); | ||
| 10055 | |||
| 10056 | 601110 | mdl_requests->push_front(mdl_request); | |
| 10057 | |||
| 10058 |
1/2✓ Branch 0 taken 601110 times.
✗ Branch 1 not taken.
|
601110 | mdl_request = new (thd->mem_root) MDL_request; |
| 10059 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 601110 times.
|
601110 | if (mdl_request == nullptr) return true; |
| 10060 | |||
| 10061 | 601110 | MDL_REQUEST_INIT(mdl_request, MDL_key::SCHEMA, fk->ref_db.str, "", | |
| 10062 | MDL_INTENTION_EXCLUSIVE, MDL_STATEMENT); | ||
| 10063 | |||
| 10064 | 601110 | mdl_requests->push_front(mdl_request); | |
| 10065 | |||
| 10066 |
2/2✓ Branch 0 taken 600766 times.
✓ Branch 1 taken 344 times.
|
601110 | if (fk_invalidator) |
| 10067 | 600766 | fk_invalidator->add(fk->ref_db.str, fk->ref_table.str, hton); | |
| 10068 | } | ||
| 10069 | } | ||
| 10070 | 706289 | return false; | |
| 10071 | } | ||
| 10072 | |||
| 10073 | 591893 | bool collect_fk_names_for_new_fks(THD *thd, const char *db_name, | |
| 10074 | const char *table_name, | ||
| 10075 | const Alter_info *alter_info, | ||
| 10076 | handlerton *hton, | ||
| 10077 | uint fk_max_generated_name_number, | ||
| 10078 | MDL_request_list *mdl_requests) { | ||
| 10079 | char table_name_lc[NAME_LEN + 1]; | ||
| 10080 |
1/2✓ Branch 0 taken 591896 times.
✗ Branch 1 not taken.
|
591893 | strmake(table_name_lc, table_name, NAME_LEN); |
| 10081 | /* | ||
| 10082 | Prepare lowercase version of table name unless it is in lower case | ||
| 10083 | already. It is to be used for producing lowercase version of FK name | ||
| 10084 | for acquiring metadata lock on it. | ||
| 10085 | */ | ||
| 10086 |
2/2✓ Branch 0 taken 576876 times.
✓ Branch 1 taken 15020 times.
|
591896 | if (lower_case_table_names == 0) |
| 10087 |
1/2✓ Branch 0 taken 576875 times.
✗ Branch 1 not taken.
|
576876 | my_casedn_str(system_charset_info, table_name_lc); |
| 10088 | |||
| 10089 |
2/2✓ Branch 0 taken 2579883 times.
✓ Branch 1 taken 591893 times.
|
3171778 | for (size_t i = 0; i < alter_info->key_list.size(); i++) { |
| 10090 |
1/2✓ Branch 0 taken 2579883 times.
✗ Branch 1 not taken.
|
2579883 | const Key_spec *key = alter_info->key_list[i]; |
| 10091 | |||
| 10092 |
2/2✓ Branch 0 taken 612799 times.
✓ Branch 1 taken 1967084 times.
|
2579883 | if (key->type == KEYTYPE_FOREIGN) { |
| 10093 | 612799 | const Foreign_key_spec *fk = down_cast<const Foreign_key_spec *>(key); | |
| 10094 | |||
| 10095 |
2/2✓ Branch 0 taken 661 times.
✓ Branch 1 taken 612138 times.
|
612799 | if (fk->has_explicit_name) { |
| 10096 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 661 times.
|
661 | assert(fk->name.str); |
| 10097 | /* | ||
| 10098 | Since foreign key names are case-insensitive we need to lowercase | ||
| 10099 | them before passing to MDL subsystem. | ||
| 10100 | */ | ||
| 10101 | char fk_name[NAME_LEN + 1]; | ||
| 10102 |
1/2✓ Branch 0 taken 661 times.
✗ Branch 1 not taken.
|
661 | strmake(fk_name, fk->name.str, NAME_LEN); |
| 10103 |
1/2✓ Branch 0 taken 661 times.
✗ Branch 1 not taken.
|
661 | my_casedn_str(system_charset_info, fk_name); |
| 10104 | |||
| 10105 |
1/2✓ Branch 0 taken 661 times.
✗ Branch 1 not taken.
|
661 | MDL_request *mdl_request = new (thd->mem_root) MDL_request; |
| 10106 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 661 times.
|
661 | if (mdl_request == nullptr) return true; |
| 10107 | |||
| 10108 |
1/2✓ Branch 0 taken 661 times.
✗ Branch 1 not taken.
|
661 | MDL_REQUEST_INIT(mdl_request, MDL_key::FOREIGN_KEY, db_name, fk_name, |
| 10109 | MDL_EXCLUSIVE, MDL_STATEMENT); | ||
| 10110 |
1/2✓ Branch 0 taken 661 times.
✗ Branch 1 not taken.
|
661 | mdl_requests->push_front(mdl_request); |
| 10111 | } else { | ||
| 10112 | // The below buffer should be sufficient for any generated name. | ||
| 10113 | char fk_name[NAME_LEN + MAX_FK_NAME_SUFFIX_LENGTH + 10 + 1]; | ||
| 10114 | |||
| 10115 | /* | ||
| 10116 | Note that the below code is in sync with generate_fk_name(). | ||
| 10117 | |||
| 10118 | Use lower-cased version of table name to generate foreign key | ||
| 10119 | name in lower-case. | ||
| 10120 | |||
| 10121 | Here we truncate generated name if it is too long. This is sufficient | ||
| 10122 | for MDL purposes. Error will be reported later in this case. | ||
| 10123 | */ | ||
| 10124 | 612138 | generate_fk_name(fk_name, sizeof(fk_name), table_name_lc, hton, | |
| 10125 | &fk_max_generated_name_number); | ||
| 10126 | |||
| 10127 |
1/2✓ Branch 0 taken 612138 times.
✗ Branch 1 not taken.
|
612138 | MDL_request *mdl_request = new (thd->mem_root) MDL_request; |
| 10128 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 612138 times.
|
612138 | if (mdl_request == nullptr) return true; |
| 10129 | |||
| 10130 |
1/2✓ Branch 0 taken 612138 times.
✗ Branch 1 not taken.
|
612138 | MDL_REQUEST_INIT(mdl_request, MDL_key::FOREIGN_KEY, db_name, fk_name, |
| 10131 | MDL_EXCLUSIVE, MDL_STATEMENT); | ||
| 10132 | |||
| 10133 |
1/2✓ Branch 0 taken 612138 times.
✗ Branch 1 not taken.
|
612138 | mdl_requests->push_front(mdl_request); |
| 10134 | } | ||
| 10135 | } | ||
| 10136 | } | ||
| 10137 | |||
| 10138 | 591893 | return false; | |
| 10139 | } | ||
| 10140 | |||
| 10141 | /** | ||
| 10142 | Implementation of SQLCOM_CREATE_TABLE. | ||
| 10143 | |||
| 10144 | Take the metadata locks (including a shared lock on the affected | ||
| 10145 | schema) and create the table. Is written to be called from | ||
| 10146 | mysql_execute_command(), to which it delegates the common parts | ||
| 10147 | with other commands (i.e. implicit commit before and after, | ||
| 10148 | close of thread tables. | ||
| 10149 | */ | ||
| 10150 | |||
| 10151 | 661764 | bool mysql_create_table(THD *thd, TABLE_LIST *create_table, | |
| 10152 | HA_CREATE_INFO *create_info, Alter_info *alter_info) { | ||
| 10153 | 661764 | bool result = false; | |
| 10154 | 661764 | bool is_trans = false; | |
| 10155 | uint not_used; | ||
| 10156 | 661764 | handlerton *post_ddl_ht = nullptr; | |
| 10157 | 661764 | bool is_pk_generated = false; | |
| 10158 | 661764 | Foreign_key_parents_invalidator fk_invalidator; | |
| 10159 |
1/2✓ Branch 0 taken 661763 times.
✗ Branch 1 not taken.
|
661763 | DBUG_TRACE; |
| 10160 | |||
| 10161 |
1/2✓ Branch 0 taken 661763 times.
✗ Branch 1 not taken.
|
661763 | handlerton *actual_hton = get_viable_handlerton_for_create( |
| 10162 | thd, create_table->table_name, *create_info); | ||
| 10163 |
2/2✓ Branch 0 taken 17 times.
✓ Branch 1 taken 661746 times.
|
661763 | if (actual_hton == nullptr) return true; |
| 10164 | |||
| 10165 | 661746 | create_info->db_type = actual_hton; | |
| 10166 | |||
| 10167 |
1/2✓ Branch 0 taken 661747 times.
✗ Branch 1 not taken.
|
661746 | dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client()); |
| 10168 | |||
| 10169 |
2/2✓ Branch 0 taken 68 times.
✓ Branch 1 taken 661679 times.
|
661747 | if (create_info->m_transactional_ddl) { |
| 10170 | /* | ||
| 10171 | Stop if START TRANSACTION is requested on table with engine that | ||
| 10172 | does not support atomic DDL. | ||
| 10173 | */ | ||
| 10174 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 67 times.
|
68 | if (!(create_info->db_type->flags & HTON_SUPPORTS_ATOMIC_DDL)) { |
| 10175 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_NOT_ALLOWED_WITH_START_TRANSACTION, MYF(0), |
| 10176 | "with engine that does not support atomic DDL."); | ||
| 10177 | 1 | result = true; | |
| 10178 | 1 | goto end; | |
| 10179 | } | ||
| 10180 | |||
| 10181 | // Stop if START TRANSACTION is requested when creating temporary table. | ||
| 10182 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 66 times.
|
67 | if (create_info->options & HA_LEX_CREATE_TMP_TABLE) { |
| 10183 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_NOT_ALLOWED_WITH_START_TRANSACTION, MYF(0), |
| 10184 | "to create temporary tables."); | ||
| 10185 | 1 | result = true; | |
| 10186 | 1 | goto end; | |
| 10187 | } | ||
| 10188 | } | ||
| 10189 | |||
| 10190 | /* | ||
| 10191 | Open or obtain "X" MDL lock on the table being created. | ||
| 10192 | To check the existence of table, lock of type "S" is obtained on the table | ||
| 10193 | and then it is upgraded to "X" if table does not exists. | ||
| 10194 | */ | ||
| 10195 |
5/6✓ Branch 0 taken 661733 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 661168 times.
✓ Branch 3 taken 565 times.
✓ Branch 4 taken 566 times.
✓ Branch 5 taken 661178 times.
|
1322924 | if (open_tables(thd, &thd->lex->query_tables, ¬_used, 0) || |
| 10196 |
2/4✓ Branch 0 taken 661179 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 661179 times.
|
661168 | thd->decide_logging_format(thd->lex->query_tables)) { |
| 10197 | 566 | result = true; | |
| 10198 | 566 | goto end; | |
| 10199 | } | ||
| 10200 | |||
| 10201 | /* Got lock. */ | ||
| 10202 |
3/4✓ Branch 0 taken 597396 times.
✓ Branch 1 taken 63780 times.
✓ Branch 2 taken 597401 times.
✗ Branch 3 not taken.
|
661178 | DEBUG_SYNC(thd, "locked_table_name"); |
| 10203 | |||
| 10204 | /* | ||
| 10205 | Do not acquire metadata locks on tables in FK relationships if | ||
| 10206 | table (or view with the same name) exists. They are not necessary | ||
| 10207 | as we won't perform any lookups on them or update of their metadata | ||
| 10208 | in this case. | ||
| 10209 | */ | ||
| 10210 |
2/2✓ Branch 0 taken 654746 times.
✓ Branch 1 taken 13 times.
|
654768 | if (!(create_table->table || create_table->is_view()) && |
| 10211 |
6/6✓ Branch 0 taken 654768 times.
✓ Branch 1 taken 6413 times.
✓ Branch 2 taken 604380 times.
✓ Branch 3 taken 50366 times.
✓ Branch 4 taken 508444 times.
✓ Branch 5 taken 152728 times.
|
1920320 | !(create_info->options & HA_LEX_CREATE_TMP_TABLE) && |
| 10212 |
2/2✓ Branch 0 taken 508444 times.
✓ Branch 1 taken 95936 times.
|
604380 | (create_info->db_type->flags & HTON_SUPPORTS_FOREIGN_KEYS)) { |
| 10213 | /* | ||
| 10214 | CREATE TABLE fails under LOCK TABLES at open_tables() time if target | ||
| 10215 | table doesn't exist already. So we don't need to handle LOCK TABLES | ||
| 10216 | case here by checking that parent tables for new FKs are properly | ||
| 10217 | locked and there are no orphan child tables for which table being | ||
| 10218 | created will become parent. | ||
| 10219 | */ | ||
| 10220 |
3/4✓ Branch 0 taken 508441 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 508449 times.
✗ Branch 3 not taken.
|
508444 | assert(thd->locked_tables_mode != LTM_LOCK_TABLES && |
| 10221 | thd->locked_tables_mode != LTM_PRELOCKED_UNDER_LOCK_TABLES); | ||
| 10222 | |||
| 10223 |
1/2✓ Branch 0 taken 508446 times.
✗ Branch 1 not taken.
|
508449 | MDL_request_list mdl_requests; |
| 10224 | |||
| 10225 | 1525332 | if (collect_fk_parents_for_new_fks(thd, create_table->db, | |
| 10226 | create_table->table_name, alter_info, | ||
| 10227 | MDL_EXCLUSIVE, create_info->db_type, | ||
| 10228 | 1525334 | &mdl_requests, &fk_invalidator) || | |
| 10229 |
8/18✓ Branch 0 taken 508445 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 508441 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 508445 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 508448 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 102101 times.
✓ Branch 9 taken 406347 times.
✓ Branch 10 taken 508451 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 508451 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
|
1016885 | (!dd::get_dictionary()->is_dd_table_name(create_table->db, |
| 10230 | 102104 | create_table->table_name) && | |
| 10231 |
3/4✓ Branch 0 taken 102104 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 102103 times.
✓ Branch 3 taken 1 times.
|
102101 | collect_fk_children(thd, create_table->db, create_table->table_name, |
| 10232 | create_info->db_type, MDL_EXCLUSIVE, | ||
| 10233 | 508447 | &mdl_requests)) || | |
| 10234 |
2/4✓ Branch 0 taken 508447 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 508448 times.
✗ Branch 3 not taken.
|
508450 | collect_fk_names_for_new_fks(thd, create_table->db, |
| 10235 | create_table->table_name, alter_info, | ||
| 10236 | create_info->db_type, | ||
| 10237 | 0, // No pre-existing FKs | ||
| 10238 |
4/6✓ Branch 0 taken 508435 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 508435 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 508449 times.
✓ Branch 5 taken 1 times.
|
1016896 | &mdl_requests) || |
| 10239 |
2/2✓ Branch 0 taken 288801 times.
✓ Branch 1 taken 219649 times.
|
508448 | (!mdl_requests.is_empty() && |
| 10240 |
2/4✓ Branch 0 taken 288801 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 288801 times.
|
288801 | thd->mdl_context.acquire_locks(&mdl_requests, |
| 10241 | thd->variables.lock_wait_timeout))) { | ||
| 10242 | ✗ | result = true; | |
| 10243 | ✗ | goto end; | |
| 10244 | } | ||
| 10245 | } | ||
| 10246 | |||
| 10247 | // Prepare check constraints. | ||
| 10248 |
3/4✓ Branch 0 taken 661179 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 63 times.
✓ Branch 3 taken 661116 times.
|
661179 | if (prepare_check_constraints_for_create( |
| 10249 | thd, create_table->db, create_table->table_name, alter_info)) { | ||
| 10250 | 63 | result = true; | |
| 10251 | 63 | goto end; | |
| 10252 | } | ||
| 10253 | |||
| 10254 | /* | ||
| 10255 | Promote first timestamp column, when explicit_defaults_for_timestamp | ||
| 10256 | is not set | ||
| 10257 | */ | ||
| 10258 |
2/2✓ Branch 0 taken 123 times.
✓ Branch 1 taken 660993 times.
|
661116 | if (!thd->variables.explicit_defaults_for_timestamp) |
| 10259 |
1/2✓ Branch 0 taken 123 times.
✗ Branch 1 not taken.
|
123 | promote_first_timestamp_column(&alter_info->create_list); |
| 10260 | |||
| 10261 | /* | ||
| 10262 | If mode to generate invisible primary key is active then, generate primary | ||
| 10263 | key for the table. | ||
| 10264 | */ | ||
| 10265 |
5/6✓ Branch 0 taken 661112 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 96 times.
✓ Branch 3 taken 661016 times.
✓ Branch 4 taken 83 times.
✓ Branch 5 taken 661029 times.
|
661212 | if (is_generate_invisible_primary_key_mode_active(thd) && |
| 10266 |
3/4✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 83 times.
✓ Branch 3 taken 13 times.
|
96 | is_candidate_table_for_invisible_primary_key_generation(create_info, |
| 10267 | alter_info)) { | ||
| 10268 |
3/4✓ Branch 0 taken 83 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 79 times.
|
83 | if (validate_and_generate_invisible_primary_key(thd, alter_info)) { |
| 10269 | 4 | result = true; | |
| 10270 | 4 | goto end; | |
| 10271 | } | ||
| 10272 | 79 | is_pk_generated = true; | |
| 10273 | } | ||
| 10274 | |||
| 10275 |
1/2✓ Branch 0 taken 661087 times.
✗ Branch 1 not taken.
|
661108 | result = mysql_create_table_no_lock( |
| 10276 | thd, create_table->db, create_table->table_name, create_info, alter_info, | ||
| 10277 | 0, | ||
| 10278 | /* | ||
| 10279 | We don't need to find parent keys for | ||
| 10280 | FK constraints if table exists. | ||
| 10281 | */ | ||
| 10282 |
4/4✓ Branch 0 taken 654701 times.
✓ Branch 1 taken 6407 times.
✓ Branch 2 taken 654688 times.
✓ Branch 3 taken 13 times.
|
661108 | !(create_table->table || create_table->is_view()), &is_trans, |
| 10283 | &post_ddl_ht); | ||
| 10284 | |||
| 10285 | /* | ||
| 10286 | Don't write statement if: | ||
| 10287 | - Table creation has failed | ||
| 10288 | - Row-based logging is used and we are creating a temporary table | ||
| 10289 | Otherwise, the statement shall be binlogged. | ||
| 10290 | */ | ||
| 10291 |
2/2✓ Branch 0 taken 657977 times.
✓ Branch 1 taken 3110 times.
|
661087 | if (!result) { |
| 10292 | /* | ||
| 10293 | CREATE TEMPORARY TABLE doesn't terminate a transaction. Calling | ||
| 10294 | stmt.mark_created_temp_table() guarantees the transaction can be binlogged | ||
| 10295 | correctly. | ||
| 10296 | */ | ||
| 10297 |
2/2✓ Branch 0 taken 50305 times.
✓ Branch 1 taken 607672 times.
|
657977 | if (create_info->options & HA_LEX_CREATE_TMP_TABLE) |
| 10298 |
1/2✓ Branch 0 taken 50305 times.
✗ Branch 1 not taken.
|
50305 | thd->get_transaction()->mark_created_temp_table(Transaction_ctx::STMT); |
| 10299 | |||
| 10300 |
5/6✓ Branch 0 taken 567715 times.
✓ Branch 1 taken 90262 times.
✓ Branch 2 taken 567715 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 617998 times.
✓ Branch 5 taken 39979 times.
|
1793407 | if (!thd->is_current_stmt_binlog_format_row() || |
| 10301 | 567715 | (thd->is_current_stmt_binlog_format_row() && | |
| 10302 |
2/2✓ Branch 0 taken 527736 times.
✓ Branch 1 taken 39979 times.
|
567715 | !(create_info->options & HA_LEX_CREATE_TMP_TABLE))) { |
| 10303 |
1/2✓ Branch 0 taken 617998 times.
✗ Branch 1 not taken.
|
617998 | thd->add_to_binlog_accessed_dbs(create_table->db); |
| 10304 | |||
| 10305 | /* | ||
| 10306 | If primary key is generated for a table then we create version of CREATE | ||
| 10307 | TABLE statement which includes generated key and invisible column | ||
| 10308 | definitions in explicit form by calling store_create_info(). This is | ||
| 10309 | necessary to correctly binlog/replicate such statements, as we don't | ||
| 10310 | write to binary log value of @@sql_generate_invisible_primary_key | ||
| 10311 | variable, but rely on logging what really has been done instead. | ||
| 10312 | */ | ||
| 10313 |
8/8✓ Branch 0 taken 612691 times.
✓ Branch 1 taken 5307 times.
✓ Branch 2 taken 612687 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 62 times.
✓ Branch 5 taken 612625 times.
✓ Branch 6 taken 62 times.
✓ Branch 7 taken 617936 times.
|
617998 | if ((create_table->table == nullptr && !create_table->is_view()) && |
| 10314 | is_pk_generated) { | ||
| 10315 | /* | ||
| 10316 | Open table to generate CREATE TABLE statement. For non-temporary | ||
| 10317 | table we already have exclusive lock here. | ||
| 10318 | */ | ||
| 10319 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 61 times.
|
62 | if (create_info->options & HA_LEX_CREATE_TMP_TABLE) { |
| 10320 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | result = open_temporary_table(thd, create_table); |
| 10321 | } else { | ||
| 10322 |
1/2✓ Branch 0 taken 61 times.
✗ Branch 1 not taken.
|
61 | Open_table_context ot_ctx(thd, MYSQL_OPEN_REOPEN); |
| 10323 |
1/2✓ Branch 0 taken 61 times.
✗ Branch 1 not taken.
|
61 | result = open_table(thd, create_table, &ot_ctx); |
| 10324 | |||
| 10325 | // Play safe, remove uncommitted table share from the cache. | ||
| 10326 |
1/2✓ Branch 0 taken 61 times.
✗ Branch 1 not taken.
|
61 | tdc_remove_table(thd, TDC_RT_REMOVE_NOT_OWN, create_table->db, |
| 10327 | create_table->table_name, false); | ||
| 10328 | } | ||
| 10329 | |||
| 10330 |
1/2✓ Branch 0 taken 62 times.
✗ Branch 1 not taken.
|
62 | if (!result) { |
| 10331 | char buf[2048]; | ||
| 10332 | 62 | String query(buf, sizeof(buf), system_charset_info); | |
| 10333 | 62 | query.length(0); | |
| 10334 |
1/2✓ Branch 0 taken 62 times.
✗ Branch 1 not taken.
|
62 | result = store_create_info(thd, create_table, &query, create_info, |
| 10335 | true /* show_database */, | ||
| 10336 | false /* SHOW CREATE TABLE */); | ||
| 10337 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 62 times.
|
62 | assert(result == 0); // store_create_info() always return 0 |
| 10338 | |||
| 10339 | // Write generated CREATE TABLE statement to binlog. | ||
| 10340 | 62 | result = | |
| 10341 |
1/2✓ Branch 0 taken 62 times.
✗ Branch 1 not taken.
|
62 | write_bin_log(thd, true, query.ptr(), query.length(), is_trans); |
| 10342 | |||
| 10343 | /* | ||
| 10344 | Handle TABLE instance created for the non-temporary table here to | ||
| 10345 | avoid problems on transaction rollback. close_thread_table() at the | ||
| 10346 | end of statement will take care about the TABLE instance created | ||
| 10347 | for the temporary table. | ||
| 10348 | */ | ||
| 10349 |
2/2✓ Branch 0 taken 61 times.
✓ Branch 1 taken 1 times.
|
62 | if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE)) { |
| 10350 | /* | ||
| 10351 | close_thread_table() will take care about the TABLE instance we | ||
| 10352 | might have created for the non-temporary table, unless we are | ||
| 10353 | under LOCK TABLES. However, creation of non-temporary table is | ||
| 10354 | not allowed under LOCK TABLES. So we can't get here under LOCK | ||
| 10355 | TABLES. | ||
| 10356 | */ | ||
| 10357 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 61 times.
|
61 | assert(!thd->locked_tables_mode); |
| 10358 |
1/2✓ Branch 0 taken 61 times.
✗ Branch 1 not taken.
|
61 | close_thread_table(thd, &thd->open_tables); |
| 10359 | 61 | create_table->table = nullptr; | |
| 10360 | } | ||
| 10361 | 62 | } | |
| 10362 | } else { | ||
| 10363 |
3/6✓ Branch 0 taken 617936 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 617936 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 617936 times.
✗ Branch 5 not taken.
|
617936 | result = write_bin_log(thd, true, thd->query().str, thd->query().length, |
| 10364 | is_trans); | ||
| 10365 | } | ||
| 10366 | } | ||
| 10367 | } | ||
| 10368 | |||
| 10369 |
2/2✓ Branch 0 taken 50440 times.
✓ Branch 1 taken 610647 times.
|
661087 | if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE)) { |
| 10370 |
8/8✓ Branch 0 taken 604306 times.
✓ Branch 1 taken 6341 times.
✓ Branch 2 taken 604293 times.
✓ Branch 3 taken 13 times.
✓ Branch 4 taken 602410 times.
✓ Branch 5 taken 1883 times.
✓ Branch 6 taken 506913 times.
✓ Branch 7 taken 103734 times.
|
1213057 | if (!(create_table->table || create_table->is_view()) && !result && |
| 10371 |
2/2✓ Branch 0 taken 506913 times.
✓ Branch 1 taken 95497 times.
|
602410 | (create_info->db_type->flags & HTON_SUPPORTS_FOREIGN_KEYS)) { |
| 10372 |
6/10✓ Branch 0 taken 506913 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 506913 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 506913 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 506913 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 100568 times.
✓ Branch 9 taken 406345 times.
|
506913 | if (!dd::get_dictionary()->is_dd_table_name(create_table->db, |
| 10373 | create_table->table_name)) { | ||
| 10374 | 100568 | const dd::Table *new_table = nullptr; | |
| 10375 | |||
| 10376 |
4/8✓ Branch 0 taken 100568 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 100568 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 100568 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 100568 times.
|
100568 | if (thd->dd_client()->acquire(create_table->db, |
| 10377 | create_table->table_name, &new_table)) | ||
| 10378 | ✗ | result = true; | |
| 10379 | else { | ||
| 10380 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 100568 times.
|
100568 | assert(new_table != nullptr); |
| 10381 | // Check for usage of prefix key index in PARTITION BY KEY() function. | ||
| 10382 |
1/2✓ Branch 0 taken 100568 times.
✗ Branch 1 not taken.
|
100568 | dd::warn_on_deprecated_prefix_key_partition(thd, create_table->db, |
| 10383 | create_table->table_name, | ||
| 10384 | new_table, false); | ||
| 10385 | /* | ||
| 10386 | If we are to support FKs for storage engines which don't support | ||
| 10387 | atomic DDL we need to decide what to do for such SEs in case of | ||
| 10388 | failure to update children definitions and adjust code accordingly. | ||
| 10389 | */ | ||
| 10390 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 100568 times.
|
100568 | assert(is_trans); |
| 10391 | |||
| 10392 |
1/2✓ Branch 0 taken 100568 times.
✗ Branch 1 not taken.
|
100568 | if (adjust_fk_children_after_parent_def_change( |
| 10393 | thd, create_table->db, create_table->table_name, | ||
| 10394 |
4/4✓ Branch 0 taken 100565 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 100565 times.
|
201133 | create_info->db_type, new_table, nullptr) || |
| 10395 |
2/4✓ Branch 0 taken 100565 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 100565 times.
|
100565 | adjust_fk_parents(thd, create_table->db, create_table->table_name, |
| 10396 | true, nullptr)) | ||
| 10397 | 3 | result = true; | |
| 10398 | } | ||
| 10399 | } | ||
| 10400 | } | ||
| 10401 | |||
| 10402 | // Update view metadata. | ||
| 10403 |
2/2✓ Branch 0 taken 607667 times.
✓ Branch 1 taken 2980 times.
|
610647 | if (!result) { |
| 10404 |
1/2✓ Branch 0 taken 607667 times.
✗ Branch 1 not taken.
|
607667 | Uncommitted_tables_guard uncommitted_tables(thd); |
| 10405 | |||
| 10406 |
6/6✓ Branch 0 taken 602411 times.
✓ Branch 1 taken 5256 times.
✓ Branch 2 taken 602407 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 602407 times.
✓ Branch 5 taken 5260 times.
|
607667 | if (!create_table->table && !create_table->is_view()) |
| 10407 |
1/2✓ Branch 0 taken 602407 times.
✗ Branch 1 not taken.
|
602407 | uncommitted_tables.add_table(create_table); |
| 10408 | |||
| 10409 |
1/2✓ Branch 0 taken 607667 times.
✗ Branch 1 not taken.
|
607667 | result = update_referencing_views_metadata(thd, create_table, !is_trans, |
| 10410 | &uncommitted_tables); | ||
| 10411 | 607667 | } | |
| 10412 | |||
| 10413 | /* | ||
| 10414 | Initialize the create select context with details required to perform | ||
| 10415 | rollback and commit operation after the INSERT's are executed. The | ||
| 10416 | context is freed once transaction is rolled back or committed. | ||
| 10417 | |||
| 10418 | We do it just before transaction commit, so that if there is some | ||
| 10419 | error while creating a table, we can skip this initialization. One | ||
| 10420 | reason to do it this way is that the open_tables() acquires S mdl lock | ||
| 10421 | on table name and then later upgrade lock to X. If there is a error | ||
| 10422 | before the lock upgrade, we would have held S mdl lock, but then | ||
| 10423 | attempt to call tdc_remove_table() would assert during call to | ||
| 10424 | m_transactional_ddl.rollback(). | ||
| 10425 | */ | ||
| 10426 |
4/4✓ Branch 0 taken 607667 times.
✓ Branch 1 taken 2980 times.
✓ Branch 2 taken 63 times.
✓ Branch 3 taken 607604 times.
|
610647 | if (!result && create_info->m_transactional_ddl) { |
| 10427 |
2/4✓ Branch 0 taken 63 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 63 times.
✗ Branch 3 not taken.
|
63 | thd->m_transactional_ddl.init(create_table->db, create_table->table_name, |
| 10428 |
1/2✓ Branch 0 taken 63 times.
✗ Branch 1 not taken.
|
63 | create_info->db_type); |
| 10429 | } | ||
| 10430 | |||
| 10431 | /* | ||
| 10432 | Unless we are executing CREATE TEMPORARY TABLE we need to commit | ||
| 10433 | changes to the data-dictionary, SE and binary log and possibly run | ||
| 10434 | handlerton's post-DDL hook. | ||
| 10435 | |||
| 10436 | Also, ignore implicit commit of transaction if we are processing | ||
| 10437 | transactional DDL. | ||
| 10438 | */ | ||
| 10439 |
6/6✓ Branch 0 taken 607667 times.
✓ Branch 1 taken 2980 times.
✓ Branch 2 taken 590360 times.
✓ Branch 3 taken 17307 times.
✓ Branch 4 taken 590360 times.
✓ Branch 5 taken 20287 times.
|
610647 | if (!result && !thd->is_plugin_fake_ddl()) |
| 10440 |
2/4✓ Branch 0 taken 590360 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 590360 times.
✗ Branch 3 not taken.
|
1180703 | result = trans_commit_stmt(thd) || |
| 10441 |
2/2✓ Branch 0 taken 590297 times.
✓ Branch 1 taken 63 times.
|
590360 | (create_info->m_transactional_ddl ? false |
| 10442 |
3/4✓ Branch 0 taken 590280 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 590279 times.
|
590297 | : trans_commit_implicit(thd)); |
| 10443 | |||
| 10444 |
5/6✓ Branch 0 taken 2981 times.
✓ Branch 1 taken 607649 times.
✓ Branch 2 taken 2981 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2981 times.
✓ Branch 5 taken 607649 times.
|
610630 | if (result && !thd->is_plugin_fake_ddl()) { |
| 10445 |
1/2✓ Branch 0 taken 2981 times.
✗ Branch 1 not taken.
|
2981 | trans_rollback_stmt(thd); |
| 10446 | /* | ||
| 10447 | Full rollback in case we have THD::transaction_rollback_request | ||
| 10448 | and to synchronize DD state in cache and on disk (as statement | ||
| 10449 | rollback doesn't clear DD cache of modified uncommitted objects). | ||
| 10450 | */ | ||
| 10451 |
1/2✓ Branch 0 taken 2981 times.
✗ Branch 1 not taken.
|
2981 | trans_rollback(thd); |
| 10452 | } | ||
| 10453 | |||
| 10454 | /* | ||
| 10455 | In case of CREATE TABLE post-DDL hook is mostly relevant for case | ||
| 10456 | when statement is rolled back. In such cases it is responsibility | ||
| 10457 | of this hook to cleanup files which might be left after failed | ||
| 10458 | table creation attempt. Ignore calling post-DDL hoot if we are | ||
| 10459 | processing transactional DDL. | ||
| 10460 | */ | ||
| 10461 |
4/4✓ Branch 0 taken 610566 times.
✓ Branch 1 taken 64 times.
✓ Branch 2 taken 114149 times.
✓ Branch 3 taken 496417 times.
|
610630 | if (!create_info->m_transactional_ddl && post_ddl_ht) |
| 10462 |
1/2✓ Branch 0 taken 114149 times.
✗ Branch 1 not taken.
|
114149 | post_ddl_ht->post_ddl(thd); |
| 10463 | |||
| 10464 |
2/2✓ Branch 0 taken 607650 times.
✓ Branch 1 taken 2980 times.
|
610630 | if (!result) { |
| 10465 | /* | ||
| 10466 | Don't try to invalidate on error as it might be caused by | ||
| 10467 | failure to acquire locks needed for invalidation. | ||
| 10468 | */ | ||
| 10469 |
1/2✓ Branch 0 taken 607650 times.
✗ Branch 1 not taken.
|
607650 | fk_invalidator.invalidate(thd); |
| 10470 | } | ||
| 10471 | } | ||
| 10472 | |||
| 10473 | 50440 | end: | |
| 10474 | 661705 | return result; | |
| 10475 | 661722 | } | |
| 10476 | |||
| 10477 | /* | ||
| 10478 | ** Give the key name after the first field with an optional '_#' after | ||
| 10479 | **/ | ||
| 10480 | |||
| 10481 | 1930915 | static bool check_if_keyname_exists(const char *name, KEY *start, KEY *end) { | |
| 10482 |
2/2✓ Branch 0 taken 4725575 times.
✓ Branch 1 taken 1844355 times.
|
6569930 | for (KEY *key = start; key != end; key++) |
| 10483 |
2/2✓ Branch 0 taken 86560 times.
✓ Branch 1 taken 4639015 times.
|
4725575 | if (!my_strcasecmp(system_charset_info, name, key->name)) return true; |
| 10484 | 1844355 | return false; | |
| 10485 | } | ||
| 10486 | |||
| 10487 | 879810 | static const char *make_unique_key_name(const char *field_name, KEY *start, | |
| 10488 | KEY *end) { | ||
| 10489 | char buff[MAX_FIELD_NAME], *buff_end; | ||
| 10490 | |||
| 10491 |
5/6✓ Branch 0 taken 879810 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 795612 times.
✓ Branch 3 taken 84198 times.
✓ Branch 4 taken 795608 times.
✓ Branch 5 taken 84202 times.
|
1675422 | if (!check_if_keyname_exists(field_name, start, end) && |
| 10492 |
3/4✓ Branch 0 taken 795612 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 795608 times.
✓ Branch 3 taken 4 times.
|
795612 | my_strcasecmp(system_charset_info, field_name, primary_key_name)) |
| 10493 | 795608 | return field_name; // Use fieldname | |
| 10494 |
1/2✓ Branch 0 taken 84202 times.
✗ Branch 1 not taken.
|
84202 | buff_end = strmake(buff, field_name, sizeof(buff) - 4); |
| 10495 | |||
| 10496 | /* | ||
| 10497 | Only 3 chars + '\0' left, so need to limit to 2 digit | ||
| 10498 | This is ok as we can't have more than 100 keys anyway | ||
| 10499 | */ | ||
| 10500 |
1/2✓ Branch 0 taken 85575 times.
✗ Branch 1 not taken.
|
85575 | for (uint i = 2; i < 100; i++) { |
| 10501 | 85575 | *buff_end = '_'; | |
| 10502 |
1/2✓ Branch 0 taken 85575 times.
✗ Branch 1 not taken.
|
85575 | longlong10_to_str(i, buff_end + 1, 10); |
| 10503 |
4/6✓ Branch 0 taken 85575 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84202 times.
✓ Branch 3 taken 1373 times.
✓ Branch 4 taken 84202 times.
✗ Branch 5 not taken.
|
85575 | if (!check_if_keyname_exists(buff, start, end)) return sql_strdup(buff); |
| 10504 | } | ||
| 10505 | ✗ | return "not_specified"; // Should never happen | |
| 10506 | } | ||
| 10507 | |||
| 10508 | /* Ignore errors related to invalid collation during rename table. */ | ||
| 10509 | class Rename_table_error_handler : public Internal_error_handler { | ||
| 10510 | public: | ||
| 10511 | 7 | bool handle_condition(THD *, uint sql_errno, const char *, | |
| 10512 | Sql_condition::enum_severity_level *, | ||
| 10513 | const char *) override { | ||
| 10514 |
2/4✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
|
7 | return (sql_errno == ER_UNKNOWN_COLLATION || |
| 10515 | 7 | sql_errno == ER_PLUGIN_IS_NOT_LOADED); | |
| 10516 | } | ||
| 10517 | }; | ||
| 10518 | |||
| 10519 | /**************************************************************************** | ||
| 10520 | ** Alter a table definition | ||
| 10521 | ****************************************************************************/ | ||
| 10522 | |||
| 10523 | /** | ||
| 10524 | Rename histograms from an old table name to a new table name. | ||
| 10525 | |||
| 10526 | @param thd Thread handle | ||
| 10527 | @param old_schema_name The old schema name | ||
| 10528 | @param old_table_name The old table name | ||
| 10529 | @param new_schema_name The new schema name | ||
| 10530 | @param new_table_name The new table name | ||
| 10531 | |||
| 10532 | @return false on success, true on error | ||
| 10533 | */ | ||
| 10534 | 2404 | static bool rename_histograms(THD *thd, const char *old_schema_name, | |
| 10535 | const char *old_table_name, | ||
| 10536 | const char *new_schema_name, | ||
| 10537 | const char *new_table_name) { | ||
| 10538 | 2404 | histograms::results_map results; | |
| 10539 | bool res = | ||
| 10540 |
1/2✓ Branch 0 taken 2404 times.
✗ Branch 1 not taken.
|
2404 | histograms::rename_histograms(thd, old_schema_name, old_table_name, |
| 10541 | new_schema_name, new_table_name, results); | ||
| 10542 | |||
| 10543 |
4/6✓ Branch 0 taken 2404 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2403 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
2404 | DBUG_EXECUTE_IF("fail_after_rename_histograms", { |
| 10544 | my_error(ER_UNABLE_TO_UPDATE_COLUMN_STATISTICS, MYF(0), "dummy_column", | ||
| 10545 | old_schema_name, old_table_name); | ||
| 10546 | res = true; | ||
| 10547 | }); | ||
| 10548 | 2404 | return res; | |
| 10549 | 2404 | } | |
| 10550 | |||
| 10551 | /** | ||
| 10552 | Drop histograms from a given table. | ||
| 10553 | |||
| 10554 | This function will check if an ALTER TABLE statement will make a histogram | ||
| 10555 | invalid: | ||
| 10556 | - Removing columns | ||
| 10557 | - Changing columns (data type, collation and such) | ||
| 10558 | - Adding UNIQUE index | ||
| 10559 | |||
| 10560 | If such change is found, remove any existing histogram for these columns. | ||
| 10561 | |||
| 10562 | @param thd thread handler | ||
| 10563 | @param table the table given in ALTER TABLE | ||
| 10564 | @param alter_info the alter changes to be carried out by ALTER TABLE | ||
| 10565 | @param create_info the alter changes to be carried out by ALTER TABLE | ||
| 10566 | @param columns a list of columns to be changed or dropped | ||
| 10567 | @param original_table_def the table definition, pre altering. Note that the | ||
| 10568 | name returned by original_table_def->name() might | ||
| 10569 | not be the same as table->table_name, since this may | ||
| 10570 | be a backup table object with an auto-generated name | ||
| 10571 | @param altered_table_def the table definition, post altering | ||
| 10572 | |||
| 10573 | @return false on success, true on error | ||
| 10574 | */ | ||
| 10575 | 75389 | static bool alter_table_drop_histograms(THD *thd, TABLE_LIST *table, | |
| 10576 | Alter_info *alter_info, | ||
| 10577 | HA_CREATE_INFO *create_info, | ||
| 10578 | histograms::columns_set &columns, | ||
| 10579 | const dd::Table *original_table_def, | ||
| 10580 | const dd::Table *altered_table_def) { | ||
| 10581 | 75389 | bool alter_drop_column = | |
| 10582 | 75389 | (alter_info->flags & | |
| 10583 | (Alter_info::ALTER_DROP_COLUMN | Alter_info::ALTER_CHANGE_COLUMN)); | ||
| 10584 | 75389 | bool convert_character_set = | |
| 10585 |
2/2✓ Branch 0 taken 27743 times.
✓ Branch 1 taken 47646 times.
|
103132 | (alter_info->flags & Alter_info::ALTER_OPTIONS) && |
| 10586 |
2/2✓ Branch 0 taken 1950 times.
✓ Branch 1 taken 25793 times.
|
27743 | (create_info->used_fields & HA_CREATE_USED_CHARSET); |
| 10587 | |||
| 10588 | 75389 | bool encryption_enabled = false; | |
| 10589 |
4/6✓ Branch 0 taken 75389 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 75389 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 60423 times.
✓ Branch 5 taken 14966 times.
|
75389 | if (altered_table_def->options().exists("encrypt_type")) { |
| 10590 | 60423 | dd::String_type str; | |
| 10591 |
3/6✓ Branch 0 taken 60423 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 60423 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 60423 times.
✗ Branch 5 not taken.
|
60423 | (void)altered_table_def->options().get("encrypt_type", &str); |
| 10592 | |||
| 10593 | 60423 | encryption_enabled = | |
| 10594 |
1/2✓ Branch 0 taken 60423 times.
✗ Branch 1 not taken.
|
60423 | 0 != my_strcasecmp(system_charset_info, "n", str.c_str()); |
| 10595 | 60423 | } | |
| 10596 | |||
| 10597 | 75389 | bool single_part_unique_index = false; | |
| 10598 | /* | ||
| 10599 | Check if we are adding a single-part unique index for a column. If we are, | ||
| 10600 | remove any existing histogram for that column. | ||
| 10601 | */ | ||
| 10602 |
2/2✓ Branch 0 taken 12245 times.
✓ Branch 1 taken 63144 times.
|
75389 | if (alter_info->flags & Alter_info::ALTER_ADD_INDEX) { |
| 10603 |
6/10✓ Branch 0 taken 12245 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12245 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12245 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 28075 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 28075 times.
✓ Branch 9 taken 12245 times.
|
40320 | for (const auto key : altered_table_def->indexes()) { |
| 10604 | /* | ||
| 10605 | A key may have multiple elements, such as (DB_ROW_ID, column). So, check | ||
| 10606 | if we only have a single visible element in the unique/primary key. | ||
| 10607 | */ | ||
| 10608 | 94535 | auto not_hidden = [](const dd::Index_element *element) { | |
| 10609 | 94535 | return !element->is_hidden(); | |
| 10610 | }; | ||
| 10611 |
1/2✓ Branch 0 taken 28075 times.
✗ Branch 1 not taken.
|
28075 | if ((key->type() == dd::Index::IT_PRIMARY || |
| 10612 |
7/8✓ Branch 0 taken 23734 times.
✓ Branch 1 taken 4341 times.
✓ Branch 2 taken 23734 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10918 times.
✓ Branch 5 taken 12816 times.
✓ Branch 6 taken 9110 times.
✓ Branch 7 taken 18965 times.
|
43334 | key->type() == dd::Index::IT_UNIQUE) && |
| 10613 |
7/12✓ Branch 0 taken 15259 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15259 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15259 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 15259 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 15259 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 9110 times.
✓ Branch 11 taken 6149 times.
|
15259 | std::count_if(key->elements().begin(), key->elements().end(), |
| 10614 | not_hidden) == 1) { | ||
| 10615 | 9110 | single_part_unique_index = true; | |
| 10616 |
1/2✓ Branch 0 taken 9110 times.
✗ Branch 1 not taken.
|
9110 | const dd::Index_element *element = *std::find_if( |
| 10617 |
5/10✓ Branch 0 taken 9110 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9110 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9110 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 9110 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 9110 times.
✗ Branch 9 not taken.
|
18220 | key->elements().begin(), key->elements().end(), not_hidden); |
| 10618 |
3/6✓ Branch 0 taken 9110 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9110 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9110 times.
✗ Branch 5 not taken.
|
9110 | columns.emplace(element->column().name().c_str()); |
| 10619 | } | ||
| 10620 | } | ||
| 10621 | } | ||
| 10622 | |||
| 10623 | /* | ||
| 10624 | If we are changing the character set, find all character columns. TEXT and | ||
| 10625 | similar types will be converted similarly as a BLOB/LONG_BLOB etc. but with | ||
| 10626 | a non-binary character set. | ||
| 10627 | */ | ||
| 10628 |
2/2✓ Branch 0 taken 1950 times.
✓ Branch 1 taken 73439 times.
|
75389 | if (convert_character_set) { |
| 10629 |
6/10✓ Branch 0 taken 1950 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1950 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1950 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 21453 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 21453 times.
✓ Branch 9 taken 1950 times.
|
23403 | for (const auto column : altered_table_def->columns()) { |
| 10630 |
3/4✓ Branch 0 taken 21453 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5897 times.
✓ Branch 3 taken 15556 times.
|
21453 | switch (column->type()) { |
| 10631 | 5897 | case dd::enum_column_types::STRING: | |
| 10632 | case dd::enum_column_types::VAR_STRING: | ||
| 10633 | case dd::enum_column_types::VARCHAR: | ||
| 10634 | case dd::enum_column_types::TINY_BLOB: | ||
| 10635 | case dd::enum_column_types::MEDIUM_BLOB: | ||
| 10636 | case dd::enum_column_types::LONG_BLOB: | ||
| 10637 | case dd::enum_column_types::BLOB: | ||
| 10638 |
3/4✓ Branch 0 taken 5897 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5421 times.
✓ Branch 3 taken 476 times.
|
5897 | if (column->collation_id() != my_charset_bin.number) |
| 10639 |
2/4✓ Branch 0 taken 5421 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5421 times.
✗ Branch 3 not taken.
|
5421 | columns.emplace(column->name().c_str()); |
| 10640 | 5897 | break; | |
| 10641 | 15556 | default: | |
| 10642 | 15556 | continue; | |
| 10643 | } | ||
| 10644 | } | ||
| 10645 | } | ||
| 10646 | |||
| 10647 |
8/8✓ Branch 0 taken 55727 times.
✓ Branch 1 taken 19662 times.
✓ Branch 2 taken 54725 times.
✓ Branch 3 taken 1002 times.
✓ Branch 4 taken 53644 times.
✓ Branch 5 taken 1081 times.
✓ Branch 6 taken 6833 times.
✓ Branch 7 taken 46811 times.
|
75389 | if (alter_drop_column || convert_character_set || encryption_enabled || |
| 10648 | single_part_unique_index) { | ||
| 10649 | 28578 | histograms::results_map results; | |
| 10650 | bool res; | ||
| 10651 |
2/2✓ Branch 0 taken 1400 times.
✓ Branch 1 taken 27178 times.
|
28578 | if (encryption_enabled) |
| 10652 |
1/2✓ Branch 0 taken 1400 times.
✗ Branch 1 not taken.
|
1400 | res = histograms::drop_all_histograms(thd, *table, *original_table_def, |
| 10653 | results); | ||
| 10654 | else | ||
| 10655 |
1/2✓ Branch 0 taken 27178 times.
✗ Branch 1 not taken.
|
27178 | res = histograms::drop_histograms(thd, *table, columns, false, results); |
| 10656 | |||
| 10657 |
4/6✓ Branch 0 taken 28578 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 28577 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
28578 | DBUG_EXECUTE_IF("fail_after_drop_histograms", { |
| 10658 | my_error(ER_UNABLE_TO_DROP_COLUMN_STATISTICS, MYF(0), "dummy_column", | ||
| 10659 | table->db, table->table_name); | ||
| 10660 | res = true; | ||
| 10661 | }); | ||
| 10662 | 28578 | return res; | |
| 10663 | 28578 | } | |
| 10664 | |||
| 10665 | 46811 | return false; | |
| 10666 | } | ||
| 10667 | |||
| 10668 | /** | ||
| 10669 | Rename a table. | ||
| 10670 | |||
| 10671 | @param thd Thread handle | ||
| 10672 | @param base The handlerton handle. | ||
| 10673 | @param old_db The old database name. | ||
| 10674 | @param old_name The old table name. | ||
| 10675 | @param old_fk_db The old table db to be used for | ||
| 10676 | identifying self-referencing FKs | ||
| 10677 | which need to be updated. | ||
| 10678 | @param old_fk_name The old table name to be used for | ||
| 10679 | identifying generated FK names and | ||
| 10680 | self-referencing FKs which need to | ||
| 10681 | be updated. | ||
| 10682 | @param new_schema DD object for the new schema. | ||
| 10683 | @param new_db The new database name. | ||
| 10684 | @param new_name The new table name. | ||
| 10685 | @param flags flags | ||
| 10686 | FN_FROM_IS_TMP old_name is temporary. | ||
| 10687 | FN_TO_IS_TMP new_name is temporary. | ||
| 10688 | NO_FK_CHECKS Don't check FK constraints during rename. | ||
| 10689 | NO_DD_COMMIT Don't commit transaction after updating | ||
| 10690 | data-dictionary. | ||
| 10691 | NO_FK_RENAME Don't change generated foreign key names | ||
| 10692 | during rename. | ||
| 10693 | NO_CC_RENAME Don't change generated check constraint | ||
| 10694 | names during rename. | ||
| 10695 | |||
| 10696 | @note Use of NO_DD_COMMIT flag only allowed for SEs supporting atomic DDL. | ||
| 10697 | |||
| 10698 | @note In case when NO_DD_COMMIT flag was used, the caller must rollback | ||
| 10699 | both statement and transaction on failure. This is necessary to | ||
| 10700 | revert results of handler::ha_rename_table() call in case when | ||
| 10701 | update to the data-dictionary which follows it fails. Also this must | ||
| 10702 | be done before any further accesses to DD. | ||
| 10703 | |||
| 10704 | @return false OK | ||
| 10705 | @return true Error | ||
| 10706 | */ | ||
| 10707 | |||
| 10708 | 39081 | bool mysql_rename_table(THD *thd, handlerton *base, const char *old_db, | |
| 10709 | const char *old_name, const char *old_fk_db, | ||
| 10710 | const char *old_fk_name, const dd::Schema &new_schema, | ||
| 10711 | const char *new_db, const char *new_name, uint flags) { | ||
| 10712 |
1/2✓ Branch 0 taken 39081 times.
✗ Branch 1 not taken.
|
39081 | DBUG_TRACE; |
| 10713 |
5/8✓ Branch 0 taken 39081 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39081 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✓ Branch 5 taken 39063 times.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
|
39081 | DBUG_PRINT("enter", ("old: '%s'.'%s' new: '%s'.'%s'", old_db, old_name, |
| 10714 | new_db, new_name)); | ||
| 10715 | |||
| 10716 | /* | ||
| 10717 | Only SEs which support atomic DDL are allowed not to commit | ||
| 10718 | changes to the data-dictionary. | ||
| 10719 | */ | ||
| 10720 |
3/4✓ Branch 0 taken 15120 times.
✓ Branch 1 taken 23961 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 15120 times.
|
39081 | assert(!(flags & NO_DD_COMMIT) || (base->flags & HTON_SUPPORTS_ATOMIC_DDL)); |
| 10721 | /* | ||
| 10722 | Check if the new_db database exists. The problem is that some | ||
| 10723 | SE's may not verify if new_db database exists and they might | ||
| 10724 | succeed renaming the table. Moreover, even the InnoDB engine | ||
| 10725 | succeeds renaming the table without verifying if the new_db | ||
| 10726 | database exists when innodb_file_per_table=0. | ||
| 10727 | */ | ||
| 10728 | |||
| 10729 | // Check if we hit FN_REFLEN bytes along with file extension. | ||
| 10730 | char from[FN_REFLEN + 1]; | ||
| 10731 | char to[FN_REFLEN + 1]; | ||
| 10732 | size_t length; | ||
| 10733 | bool was_truncated; | ||
| 10734 |
1/2✓ Branch 0 taken 39081 times.
✗ Branch 1 not taken.
|
39081 | build_table_filename(from, sizeof(from) - 1, old_db, old_name, "", |
| 10735 | flags & FN_FROM_IS_TMP); | ||
| 10736 |
1/2✓ Branch 0 taken 39081 times.
✗ Branch 1 not taken.
|
39081 | length = build_table_filename(to, sizeof(to) - 1, new_db, new_name, "", |
| 10737 | flags & FN_TO_IS_TMP, &was_truncated); | ||
| 10738 |
2/4✓ Branch 0 taken 39081 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 39081 times.
|
39081 | if (was_truncated || length + reg_ext_length > FN_REFLEN) { |
| 10739 | ✗ | my_error(ER_IDENT_CAUSES_TOO_LONG_PATH, MYF(0), sizeof(to) - 1, to); | |
| 10740 | ✗ | return true; | |
| 10741 | } | ||
| 10742 | |||
| 10743 |
1/2✓ Branch 0 taken 39081 times.
✗ Branch 1 not taken.
|
39081 | dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client()); |
| 10744 | 39081 | const dd::Table *from_table_def = nullptr; | |
| 10745 | 39081 | dd::Table *to_table_def = nullptr; | |
| 10746 | |||
| 10747 |
6/16✓ Branch 0 taken 39081 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39081 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 39081 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 39081 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 39081 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 39081 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
|
117243 | if (thd->dd_client()->acquire(old_db, old_name, &from_table_def) || |
| 10748 |
7/18✓ Branch 0 taken 39081 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39081 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 39081 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 39081 times.
✓ Branch 8 taken 39081 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 39081 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 39081 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
|
78162 | thd->dd_client()->acquire_for_modification(old_db, old_name, |
| 10749 | &to_table_def)) | ||
| 10750 | ✗ | return true; | |
| 10751 | |||
| 10752 | // Tables with a defined secondary engine cannot be renamed, except if the | ||
| 10753 | // renaming is only temporary, which may happen if e.g. ALGORITHM=COPY is | ||
| 10754 | // used. | ||
| 10755 |
8/14✓ Branch 0 taken 39081 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39081 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 39081 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 39078 times.
✓ Branch 8 taken 39081 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✓ Branch 11 taken 39080 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
|
39084 | if (from_table_def->options().exists("secondary_engine") && |
| 10756 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
|
3 | !(flags & FN_IS_TMP)) { |
| 10757 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_SECONDARY_ENGINE_DDL, MYF(0)); |
| 10758 | 1 | return true; | |
| 10759 | } | ||
| 10760 | |||
| 10761 | // Set schema id, table name and hidden attribute. | ||
| 10762 |
2/4✓ Branch 0 taken 39080 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39080 times.
✗ Branch 3 not taken.
|
39080 | to_table_def->set_schema_id(new_schema.id()); |
| 10763 |
2/4✓ Branch 0 taken 39080 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39080 times.
✗ Branch 3 not taken.
|
39080 | to_table_def->set_name(new_name); |
| 10764 |
3/4✓ Branch 0 taken 18373 times.
✓ Branch 1 taken 20707 times.
✓ Branch 2 taken 39080 times.
✗ Branch 3 not taken.
|
39080 | to_table_def->set_hidden((flags & FN_TO_IS_TMP) |
| 10765 | ? dd::Abstract_table::HT_HIDDEN_DDL | ||
| 10766 | : dd::Abstract_table::HT_VISIBLE); | ||
| 10767 | |||
| 10768 | /* Adjust parent table for self-referencing foreign keys. */ | ||
| 10769 |
6/10✓ Branch 0 taken 39080 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39080 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 39080 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 241 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 241 times.
✓ Branch 9 taken 39080 times.
|
39321 | for (dd::Foreign_key *fk : *(to_table_def->foreign_keys())) { |
| 10770 |
2/4✓ Branch 0 taken 241 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 241 times.
✗ Branch 3 not taken.
|
241 | if (my_strcasecmp(table_alias_charset, |
| 10771 | fk->referenced_table_schema_name().c_str(), | ||
| 10772 |
4/4✓ Branch 0 taken 227 times.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 236 times.
|
468 | old_fk_db) == 0 && |
| 10773 |
4/6✓ Branch 0 taken 227 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 227 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 222 times.
|
227 | my_strcasecmp(table_alias_charset, fk->referenced_table_name().c_str(), |
| 10774 | old_fk_name) == 0) { | ||
| 10775 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | fk->set_referenced_table_schema_name(new_db); |
| 10776 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | fk->set_referenced_table_name(new_name); |
| 10777 | } | ||
| 10778 | } | ||
| 10779 | |||
| 10780 | /* | ||
| 10781 | Unless suppressed update generated foreign key names | ||
| 10782 | (as they have table_name<SE-specific or default suffix>#### format). | ||
| 10783 | */ | ||
| 10784 |
4/4✓ Branch 0 taken 2464 times.
✓ Branch 1 taken 36616 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 39079 times.
|
41544 | if (!(flags & NO_FK_RENAME) && |
| 10785 |
3/4✓ Branch 0 taken 2464 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2463 times.
|
2464 | dd::rename_foreign_keys(thd, old_db, old_fk_name, base, new_db, |
| 10786 | to_table_def)) | ||
| 10787 | 1 | return true; | |
| 10788 | |||
| 10789 |
4/4✓ Branch 0 taken 2463 times.
✓ Branch 1 taken 36616 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 39078 times.
|
41542 | if (!(flags & NO_CC_RENAME) && |
| 10790 |
3/4✓ Branch 0 taken 2463 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2462 times.
|
2463 | dd::rename_check_constraints(old_name, to_table_def)) |
| 10791 | 1 | return true; | |
| 10792 | |||
| 10793 | // Get the handler for the table, and issue an error if we cannot load it. | ||
| 10794 | handler *file = | ||
| 10795 |
1/2✓ Branch 0 taken 39078 times.
✗ Branch 1 not taken.
|
39078 | (base == nullptr ? nullptr |
| 10796 | 39078 | : get_new_handler((TABLE_SHARE *)nullptr, | |
| 10797 |
2/4✓ Branch 0 taken 39078 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39078 times.
✗ Branch 3 not taken.
|
39078 | from_table_def->partition_type() != |
| 10798 | dd::Table::PT_NONE, | ||
| 10799 | 39078 | thd->mem_root, base)); | |
| 10800 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 39078 times.
|
39078 | if (!file) { |
| 10801 | ✗ | my_error(ER_STORAGE_ENGINE_NOT_LOADED, MYF(0), old_db, old_name); | |
| 10802 | ✗ | return true; | |
| 10803 | } | ||
| 10804 | |||
| 10805 | /* | ||
| 10806 | If lower_case_table_names == 2 (case-preserving but case-insensitive | ||
| 10807 | file system) and the storage is not HA_FILE_BASED, we need to provide | ||
| 10808 | a lowercase file name. | ||
| 10809 | */ | ||
| 10810 | char lc_from[FN_REFLEN + 1]; | ||
| 10811 | char lc_to[FN_REFLEN + 1]; | ||
| 10812 | 39078 | char *from_base = from; | |
| 10813 | 39078 | char *to_base = to; | |
| 10814 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 39078 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 39078 times.
|
39078 | if (lower_case_table_names == 2 && |
| 10815 | ✗ | !(file->ha_table_flags() & HA_FILE_BASED)) { | |
| 10816 | char tmp_name[NAME_LEN + 1]; | ||
| 10817 | ✗ | my_stpcpy(tmp_name, old_name); | |
| 10818 | ✗ | my_casedn_str(files_charset_info, tmp_name); | |
| 10819 | ✗ | build_table_filename(lc_from, sizeof(lc_from) - 1, old_db, tmp_name, "", | |
| 10820 | flags & FN_FROM_IS_TMP); | ||
| 10821 | ✗ | from_base = lc_from; | |
| 10822 | |||
| 10823 | ✗ | my_stpcpy(tmp_name, new_name); | |
| 10824 | ✗ | my_casedn_str(files_charset_info, tmp_name); | |
| 10825 | ✗ | build_table_filename(lc_to, sizeof(lc_to) - 1, new_db, tmp_name, "", | |
| 10826 | flags & FN_TO_IS_TMP); | ||
| 10827 | ✗ | to_base = lc_to; | |
| 10828 | } | ||
| 10829 | |||
| 10830 | /* | ||
| 10831 | Temporarily disable foreign key checks, if requested, while the | ||
| 10832 | handler is involved. | ||
| 10833 | */ | ||
| 10834 | 39078 | ulonglong save_bits = thd->variables.option_bits; | |
| 10835 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 39076 times.
|
39078 | if (flags & NO_FK_CHECKS) |
| 10836 | 2 | thd->variables.option_bits |= OPTION_NO_FOREIGN_KEY_CHECKS; | |
| 10837 | |||
| 10838 | 39078 | Rename_table_error_handler error_handler; | |
| 10839 |
1/2✓ Branch 0 taken 39078 times.
✗ Branch 1 not taken.
|
39078 | thd->push_internal_handler(&error_handler); |
| 10840 | int error = | ||
| 10841 |
1/2✓ Branch 0 taken 39010 times.
✗ Branch 1 not taken.
|
39078 | file->ha_rename_table(from_base, to_base, from_table_def, to_table_def); |
| 10842 |
1/2✓ Branch 0 taken 39010 times.
✗ Branch 1 not taken.
|
39010 | thd->pop_internal_handler(); |
| 10843 | |||
| 10844 | 39010 | thd->variables.option_bits = save_bits; | |
| 10845 | |||
| 10846 |
2/2✓ Branch 0 taken 26 times.
✓ Branch 1 taken 38984 times.
|
39010 | if (error != 0) { |
| 10847 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 23 times.
|
26 | if (error == HA_ERR_WRONG_COMMAND) |
| 10848 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | my_error(ER_NOT_SUPPORTED_YET, MYF(0), "ALTER TABLE"); |
| 10849 | else { | ||
| 10850 | char errbuf[MYSYS_STRERROR_SIZE]; | ||
| 10851 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
|
23 | my_error(ER_ERROR_ON_RENAME, MYF(0), from, to, error, |
| 10852 | my_strerror(errbuf, sizeof(errbuf), error)); | ||
| 10853 | } | ||
| 10854 | 26 | destroy(file); | |
| 10855 | 26 | return true; | |
| 10856 | } | ||
| 10857 | |||
| 10858 | /* | ||
| 10859 | Note that before WL#7743 we have renamed table in the data-dictionary | ||
| 10860 | before renaming it in storage engine. However with WL#7743 engines | ||
| 10861 | supporting atomic DDL are allowed to update dd::Table object describing | ||
| 10862 | new version of table in handler::rename_table(). Hence it should saved | ||
| 10863 | after this call. | ||
| 10864 | So to avoid extra calls to DD layer and to keep code simple the | ||
| 10865 | renaming of table in the DD was moved past rename in SE for all SEs. | ||
| 10866 | From crash-safety point of view order doesn't matter for engines | ||
| 10867 | supporting atomic DDL. And for engines which can't do atomic DDL in | ||
| 10868 | either case there are scenarios in which DD and SE get out of sync. | ||
| 10869 | */ | ||
| 10870 |
1/2✓ Branch 0 taken 38984 times.
✗ Branch 1 not taken.
|
38984 | bool result = thd->dd_client()->update(to_table_def); |
| 10871 | |||
| 10872 | /* | ||
| 10873 | Only rename histograms when this isn't a rename for temporary names | ||
| 10874 | (we will never have a histogram for a temporary name). | ||
| 10875 | |||
| 10876 | Note that this won't catch "ALTER TABLE ... ALGORITHM=COPY" since the COPY | ||
| 10877 | algorithm will first rename to a temporary name, and then to the final name. | ||
| 10878 | That case is handled in the function mysql_alter_table. | ||
| 10879 | */ | ||
| 10880 |
6/6✓ Branch 0 taken 38981 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 20628 times.
✓ Branch 3 taken 18353 times.
✓ Branch 4 taken 2292 times.
✓ Branch 5 taken 18336 times.
|
38984 | if (!result && !((flags & FN_TO_IS_TMP) || (flags & FN_FROM_IS_TMP))) { |
| 10881 |
1/2✓ Branch 0 taken 2292 times.
✗ Branch 1 not taken.
|
2292 | result = rename_histograms(thd, old_db, old_name, new_db, new_name); |
| 10882 | } | ||
| 10883 | |||
| 10884 |
2/2✓ Branch 0 taken 23955 times.
✓ Branch 1 taken 15029 times.
|
38984 | if (!(flags & NO_DD_COMMIT)) |
| 10885 |
1/2✓ Branch 0 taken 23955 times.
✗ Branch 1 not taken.
|
23955 | result = trans_intermediate_ddl_commit(thd, result); |
| 10886 | |||
| 10887 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 38980 times.
|
38984 | if (result) { |
| 10888 | /* | ||
| 10889 | In cases when we are executing atomic DDL it is responsibility of the | ||
| 10890 | caller to revert the changes to SE by rolling back transaction. | ||
| 10891 | |||
| 10892 | If storage engine supports atomic DDL but commit was requested by the | ||
| 10893 | caller the above call to trans_intermediate_ddl_commit() will roll | ||
| 10894 | back the transaction on failure and thus revert change to SE. | ||
| 10895 | */ | ||
| 10896 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (!(flags & NO_DD_COMMIT)) |
| 10897 | ✗ | (void)file->ha_rename_table(to_base, from_base, to_table_def, | |
| 10898 | const_cast<dd::Table *>(from_table_def)); | ||
| 10899 | 4 | destroy(file); | |
| 10900 | 4 | return true; | |
| 10901 | } | ||
| 10902 | 38980 | destroy(file); | |
| 10903 | |||
| 10904 | #ifdef HAVE_PSI_TABLE_INTERFACE | ||
| 10905 | /* | ||
| 10906 | Remove the old table share from the pfs table share array. The new table | ||
| 10907 | share will be created when the renamed table is first accessed. | ||
| 10908 | */ | ||
| 10909 | 38980 | bool temp_table = (bool)is_prefix(old_name, tmp_file_prefix); | |
| 10910 | PSI_TABLE_CALL(drop_table_share) | ||
| 10911 | 38980 | (temp_table, old_db, static_cast<int>(strlen(old_db)), old_name, | |
| 10912 |
1/2✓ Branch 0 taken 38980 times.
✗ Branch 1 not taken.
|
38980 | static_cast<int>(strlen(old_name))); |
| 10913 | #endif | ||
| 10914 | |||
| 10915 | 38980 | return false; | |
| 10916 | 39013 | } | |
| 10917 | |||
| 10918 | /* | ||
| 10919 | Create a table identical to the specified table | ||
| 10920 | |||
| 10921 | SYNOPSIS | ||
| 10922 | mysql_create_like_table() | ||
| 10923 | thd Thread object | ||
| 10924 | table Table list element for target table | ||
| 10925 | src_table Table list element for source table | ||
| 10926 | create_info Create info | ||
| 10927 | |||
| 10928 | RETURN VALUES | ||
| 10929 | false OK | ||
| 10930 | true error | ||
| 10931 | */ | ||
| 10932 | |||
| 10933 | 1189 | bool mysql_create_like_table(THD *thd, TABLE_LIST *table, TABLE_LIST *src_table, | |
| 10934 | HA_CREATE_INFO *create_info) { | ||
| 10935 |
1/2✓ Branch 0 taken 1189 times.
✗ Branch 1 not taken.
|
1189 | Alter_info local_alter_info(thd->mem_root); |
| 10936 |
1/2✓ Branch 0 taken 1189 times.
✗ Branch 1 not taken.
|
1189 | Alter_table_ctx local_alter_ctx; // Not used |
| 10937 | 1189 | bool is_trans = false; | |
| 10938 | uint not_used; | ||
| 10939 |
1/2✓ Branch 0 taken 1189 times.
✗ Branch 1 not taken.
|
1189 | Tablespace_hash_set tablespace_set(PSI_INSTRUMENT_ME); |
| 10940 | 1189 | handlerton *post_ddl_ht = nullptr; | |
| 10941 |
1/2✓ Branch 0 taken 1189 times.
✗ Branch 1 not taken.
|
1189 | dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client()); |
| 10942 | |||
| 10943 |
1/2✓ Branch 0 taken 1189 times.
✗ Branch 1 not taken.
|
1189 | DBUG_TRACE; |
| 10944 | |||
| 10945 | /* | ||
| 10946 | We the open source table to get its description in HA_CREATE_INFO | ||
| 10947 | and Alter_info objects. This also acquires a shared metadata lock | ||
| 10948 | on this table which ensures that no concurrent DDL operation will | ||
| 10949 | mess with it. | ||
| 10950 | Also in case when we create non-temporary table open_tables() | ||
| 10951 | call obtains an exclusive metadata lock on target table ensuring | ||
| 10952 | that we can safely perform table creation. | ||
| 10953 | Thus by holding both these locks we ensure that our statement is | ||
| 10954 | properly isolated from all concurrent operations which matter. | ||
| 10955 | |||
| 10956 | CREATE LIKE needs to have the logging format determined if in | ||
| 10957 | MIXED mode and creating LIKE a TEMP table. | ||
| 10958 | */ | ||
| 10959 |
5/6✓ Branch 0 taken 1189 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1171 times.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 18 times.
✓ Branch 5 taken 1171 times.
|
2360 | if (open_tables(thd, &thd->lex->query_tables, ¬_used, 0) || |
| 10960 |
2/4✓ Branch 0 taken 1171 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1171 times.
|
1171 | thd->decide_logging_format(thd->lex->query_tables)) |
| 10961 | 18 | return true; | |
| 10962 |
1/2✓ Branch 0 taken 1171 times.
✗ Branch 1 not taken.
|
1171 | src_table->table->use_all_columns(); |
| 10963 | |||
| 10964 | 1171 | const dd::Table *src_table_obj = nullptr; | |
| 10965 |
2/2✓ Branch 0 taken 1106 times.
✓ Branch 1 taken 65 times.
|
1171 | if (!src_table->table->s->tmp_table) { |
| 10966 |
4/8✓ Branch 0 taken 1106 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1106 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1106 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1106 times.
|
1106 | if (thd->dd_client()->acquire(src_table->db, src_table->table_name, |
| 10967 | &src_table_obj)) { | ||
| 10968 | ✗ | return true; | |
| 10969 | } | ||
| 10970 | // Should not happen, we know the table exists and can be opened. | ||
| 10971 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1106 times.
|
1106 | assert(src_table_obj != nullptr); |
| 10972 | } | ||
| 10973 | |||
| 10974 |
2/4✓ Branch 0 taken 1171 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1171 times.
✗ Branch 3 not taken.
|
1171 | DEBUG_SYNC(thd, "create_table_like_after_open"); |
| 10975 | |||
| 10976 | /* Fill HA_CREATE_INFO and Alter_info with description of source table. */ | ||
| 10977 |
1/2✓ Branch 0 taken 1171 times.
✗ Branch 1 not taken.
|
1171 | HA_CREATE_INFO local_create_info; |
| 10978 |
1/2✓ Branch 0 taken 1171 times.
✗ Branch 1 not taken.
|
1171 | local_create_info.db_type = get_viable_handlerton_for_create_like( |
| 10979 |
1/2✓ Branch 0 taken 1171 times.
✗ Branch 1 not taken.
|
1171 | thd, table->table_name, *create_info, src_table->table->s->db_type()); |
| 10980 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1168 times.
|
1171 | if (local_create_info.db_type == nullptr) return true; |
| 10981 | |||
| 10982 | // This should be ok even if engine substitution has taken place since | ||
| 10983 | // row_type denontes the desired row_type, and a different row_type may be | ||
| 10984 | // assigned to real_row_type later. | ||
| 10985 | 1168 | local_create_info.row_type = src_table->table->s->row_type; | |
| 10986 |
2/4✓ Branch 0 taken 1168 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1168 times.
|
1168 | if (mysql_prepare_alter_table(thd, src_table_obj, src_table->table, |
| 10987 | &local_create_info, &local_alter_info, | ||
| 10988 | &local_alter_ctx)) | ||
| 10989 | ✗ | return true; | |
| 10990 | |||
| 10991 |
2/4✓ Branch 0 taken 1168 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1168 times.
|
1168 | if (prepare_check_constraints_for_create_like_table(thd, src_table, table, |
| 10992 | &local_alter_info)) | ||
| 10993 | ✗ | return true; | |
| 10994 | |||
| 10995 |
5/8✓ Branch 0 taken 1168 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1168 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4955 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3787 times.
✓ Branch 7 taken 1168 times.
|
4955 | for (const Create_field &sql_field : local_alter_info.create_list) { |
| 10996 |
1/2✓ Branch 0 taken 3787 times.
✗ Branch 1 not taken.
|
3787 | warn_on_deprecated_float_precision(thd, sql_field); |
| 10997 |
1/2✓ Branch 0 taken 3787 times.
✗ Branch 1 not taken.
|
3787 | warn_on_deprecated_float_unsigned(thd, sql_field); |
| 10998 |
1/2✓ Branch 0 taken 3787 times.
✗ Branch 1 not taken.
|
3787 | warn_on_deprecated_zerofill(thd, sql_field); |
| 10999 | } | ||
| 11000 | |||
| 11001 | /* | ||
| 11002 | During open_tables(), the target tablespace name(s) for a table being | ||
| 11003 | created or altered should be locked. However, for 'CREATE TABLE ... LIKE', | ||
| 11004 | the source table is not being created, yet its tablespace name should be | ||
| 11005 | locked since it is used as the target tablespace name for the table being | ||
| 11006 | created. The target tablespace name cannot be set before open_tables() | ||
| 11007 | (which is how we handle this for e.g. CREATE TABLE ... TABLESPACE ...'), | ||
| 11008 | since before open_tables(), the source table itself is not locked, which | ||
| 11009 | means that a DDL operation may sneak in and change the tablespace of the | ||
| 11010 | source table *after* we retrieved it from the .FRM file of the source | ||
| 11011 | table, and *before* the source table itself is locked. Thus, we lock the | ||
| 11012 | target tablespace here in a separate mdl lock acquisition phase after | ||
| 11013 | open_tables(). Since the table is already opened (and locked), we retrieve | ||
| 11014 | the tablespace name from the table share instead of reading it from the | ||
| 11015 | .FRM file. | ||
| 11016 | */ | ||
| 11017 | |||
| 11018 | /* Partition info is not handled by mysql_prepare_alter_table() call. */ | ||
| 11019 |
2/2✓ Branch 0 taken 102 times.
✓ Branch 1 taken 1066 times.
|
1168 | if (src_table->table->part_info) |
| 11020 |
1/2✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
|
102 | thd->work_part_info = src_table->table->part_info->get_clone(thd); |
| 11021 | |||
| 11022 | // Add the tablespace name, if used. | ||
| 11023 |
2/2✓ Branch 0 taken 45 times.
✓ Branch 1 taken 1123 times.
|
1168 | if (src_table->table->s->tablespace && |
| 11024 |
1/2✓ Branch 0 taken 45 times.
✗ Branch 1 not taken.
|
45 | strlen(src_table->table->s->tablespace) > 0) { |
| 11025 |
4/6✓ Branch 0 taken 42 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 42 times.
|
45 | assert( |
| 11026 | src_table->table->s->tmp_table || | ||
| 11027 | thd->mdl_context.owns_equal_or_stronger_lock( | ||
| 11028 | MDL_key::TABLE, src_table->db, src_table->table_name, MDL_SHARED)); | ||
| 11029 | |||
| 11030 |
2/4✓ Branch 0 taken 45 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 45 times.
✗ Branch 3 not taken.
|
45 | tablespace_set.insert(src_table->table->s->tablespace); |
| 11031 | } | ||
| 11032 | |||
| 11033 | // Add tablespace names used under partition/subpartition definitions. | ||
| 11034 |
2/4✓ Branch 0 taken 1168 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1168 times.
|
1168 | if (fill_partition_tablespace_names(src_table->table->part_info, |
| 11035 | &tablespace_set)) | ||
| 11036 | ✗ | return true; | |
| 11037 | |||
| 11038 | /* | ||
| 11039 | After we have identified the tablespace names, we iterate | ||
| 11040 | over the names and acquire MDL lock for each of them. | ||
| 11041 | */ | ||
| 11042 |
2/4✓ Branch 0 taken 1168 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1168 times.
|
1168 | if (lock_tablespace_names(thd, &tablespace_set, |
| 11043 | thd->variables.lock_wait_timeout, thd->mem_root)) { | ||
| 11044 | ✗ | return true; | |
| 11045 | } | ||
| 11046 | |||
| 11047 | /* | ||
| 11048 | Adjust description of source table before using it for creation of | ||
| 11049 | target table. | ||
| 11050 | |||
| 11051 | Similarly to SHOW CREATE TABLE we ignore MAX_ROWS attribute of | ||
| 11052 | temporary table which represents I_S table. | ||
| 11053 | */ | ||
| 11054 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1162 times.
|
1168 | if (src_table->schema_table) local_create_info.max_rows = 0; |
| 11055 | /* Set IF NOT EXISTS option as in the CREATE TABLE LIKE statement. */ | ||
| 11056 | 1168 | local_create_info.options |= | |
| 11057 | 1168 | create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS; | |
| 11058 | /* Replace type of source table with one specified in the statement. */ | ||
| 11059 | 1168 | local_create_info.options &= ~HA_LEX_CREATE_TMP_TABLE; | |
| 11060 | 1168 | local_create_info.options |= create_info->options & HA_LEX_CREATE_TMP_TABLE; | |
| 11061 | /* Reset auto-increment counter for the new table. */ | ||
| 11062 | 1168 | local_create_info.auto_increment_value = 0; | |
| 11063 | /* | ||
| 11064 | Do not inherit values of DATA and INDEX DIRECTORY options from | ||
| 11065 | the original table. This is documented behavior. | ||
| 11066 | */ | ||
| 11067 | 1168 | local_create_info.data_file_name = local_create_info.index_file_name = | |
| 11068 | nullptr; | ||
| 11069 | 1168 | local_create_info.alias = create_info->alias; | |
| 11070 | |||
| 11071 | /* | ||
| 11072 | Keep tablespace, only if it was specified explicitly in CREATE | ||
| 11073 | TABLE when source table was created. | ||
| 11074 | */ | ||
| 11075 |
7/8✓ Branch 0 taken 1103 times.
✓ Branch 1 taken 65 times.
✓ Branch 2 taken 1103 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1066 times.
✓ Branch 5 taken 37 times.
✓ Branch 6 taken 1066 times.
✓ Branch 7 taken 102 times.
|
1168 | if (src_table_obj && !src_table_obj->is_explicit_tablespace()) { |
| 11076 | 1066 | local_create_info.tablespace = nullptr; | |
| 11077 | } | ||
| 11078 | |||
| 11079 | /* | ||
| 11080 | Lock the FK children, in case the new table introduces a missing parent. | ||
| 11081 | */ | ||
| 11082 |
1/2✓ Branch 0 taken 1152 times.
✗ Branch 1 not taken.
|
1152 | if (!(table->table || table->is_view()) && |
| 11083 |
6/6✓ Branch 0 taken 1152 times.
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 1079 times.
✓ Branch 3 taken 73 times.
✓ Branch 4 taken 834 times.
✓ Branch 5 taken 334 times.
|
3399 | !(create_info->options & HA_LEX_CREATE_TMP_TABLE) && |
| 11084 |
2/2✓ Branch 0 taken 834 times.
✓ Branch 1 taken 245 times.
|
1079 | (local_create_info.db_type->flags & HTON_SUPPORTS_FOREIGN_KEYS)) { |
| 11085 | /* | ||
| 11086 | CREATE TABLE LIKE fails under LOCK TABLES at open_tables() time if | ||
| 11087 | target table doesn't exist already. So we don't need to handle | ||
| 11088 | LOCK TABLES case here by checking that parent tables for new FKs | ||
| 11089 | are properly locked and there are no orphan child tables for which | ||
| 11090 | table being created will become parent. | ||
| 11091 | */ | ||
| 11092 |
2/4✓ Branch 0 taken 834 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 834 times.
✗ Branch 3 not taken.
|
834 | assert(thd->locked_tables_mode != LTM_LOCK_TABLES && |
| 11093 | thd->locked_tables_mode != LTM_PRELOCKED_UNDER_LOCK_TABLES); | ||
| 11094 | |||
| 11095 |
1/2✓ Branch 0 taken 834 times.
✗ Branch 1 not taken.
|
834 | MDL_request_list mdl_requests; |
| 11096 | |||
| 11097 |
3/10✓ Branch 0 taken 834 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 834 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 834 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
1668 | if ((!dd::get_dictionary()->is_dd_table_name(table->db, |
| 11098 | 834 | table->table_name) && | |
| 11099 |
2/4✓ Branch 0 taken 834 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 834 times.
✗ Branch 3 not taken.
|
834 | collect_fk_children(thd, table->db, table->table_name, |
| 11100 | local_create_info.db_type, MDL_EXCLUSIVE, | ||
| 11101 |
5/10✓ Branch 0 taken 834 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 834 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 834 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 834 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 834 times.
✗ Branch 9 not taken.
|
2502 | &mdl_requests)) || |
| 11102 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 834 times.
|
834 | (!mdl_requests.is_empty() && |
| 11103 | ✗ | thd->mdl_context.acquire_locks(&mdl_requests, | |
| 11104 | thd->variables.lock_wait_timeout))) | ||
| 11105 | ✗ | return true; | |
| 11106 | } | ||
| 11107 | |||
| 11108 |
3/4✓ Branch 0 taken 1168 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
✓ Branch 3 taken 1141 times.
|
1168 | if (mysql_create_table_no_lock( |
| 11109 | thd, table->db, table->table_name, &local_create_info, | ||
| 11110 | &local_alter_info, 0, | ||
| 11111 | false, // No FKs, no need to lookup parent keys | ||
| 11112 | &is_trans, &post_ddl_ht)) | ||
| 11113 | 27 | goto err; | |
| 11114 | |||
| 11115 | /* | ||
| 11116 | Ensure that table or view does not exist and we have an exclusive lock on | ||
| 11117 | target table if we are creating non-temporary table. In LOCK TABLES mode | ||
| 11118 | the only way the table is locked, is if it already exists (since you cannot | ||
| 11119 | LOCK TABLE a non-existing table). And the only way we then can end up here | ||
| 11120 | is if IF EXISTS was used. | ||
| 11121 | */ | ||
| 11122 |
8/20✓ Branch 0 taken 1130 times.
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 1130 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1059 times.
✓ Branch 5 taken 71 times.
✓ Branch 6 taken 1059 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1059 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1059 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
|
1141 | assert( |
| 11123 | table->table || table->is_view() || | ||
| 11124 | (create_info->options & HA_LEX_CREATE_TMP_TABLE) || | ||
| 11125 | (thd->locked_tables_mode != LTM_LOCK_TABLES && | ||
| 11126 | thd->mdl_context.owns_equal_or_stronger_lock( | ||
| 11127 | MDL_key::TABLE, table->db, table->table_name, MDL_EXCLUSIVE)) || | ||
| 11128 | (thd->locked_tables_mode == LTM_LOCK_TABLES && | ||
| 11129 | (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) && | ||
| 11130 | thd->mdl_context.owns_equal_or_stronger_lock( | ||
| 11131 | MDL_key::TABLE, table->db, table->table_name, MDL_SHARED_NO_WRITE))); | ||
| 11132 | |||
| 11133 |
2/4✓ Branch 0 taken 1141 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1141 times.
✗ Branch 3 not taken.
|
1141 | DEBUG_SYNC(thd, "create_table_like_before_binlog"); |
| 11134 | |||
| 11135 | /* | ||
| 11136 | CREATE TEMPORARY TABLE doesn't terminate a transaction. Calling | ||
| 11137 | stmt.mark_created_temp_table() guarantees the transaction can be binlogged | ||
| 11138 | correctly. | ||
| 11139 | */ | ||
| 11140 |
2/2✓ Branch 0 taken 73 times.
✓ Branch 1 taken 1068 times.
|
1141 | if (create_info->options & HA_LEX_CREATE_TMP_TABLE) |
| 11141 |
1/2✓ Branch 0 taken 73 times.
✗ Branch 1 not taken.
|
73 | thd->get_transaction()->mark_created_temp_table(Transaction_ctx::STMT); |
| 11142 | |||
| 11143 | /* | ||
| 11144 | We have to write the query before we unlock the tables. | ||
| 11145 | */ | ||
| 11146 |
7/8✓ Branch 0 taken 1141 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1102 times.
✓ Branch 3 taken 39 times.
✓ Branch 4 taken 932 times.
✓ Branch 5 taken 170 times.
✓ Branch 6 taken 932 times.
✓ Branch 7 taken 209 times.
|
2243 | if (!thd->is_current_stmt_binlog_disabled() && |
| 11147 | 1102 | thd->is_current_stmt_binlog_format_row()) { | |
| 11148 | /* | ||
| 11149 | Since temporary tables are not replicated under row-based | ||
| 11150 | replication, CREATE TABLE ... LIKE ... needs special | ||
| 11151 | treatment. We have four cases to consider, according to the | ||
| 11152 | following decision table: | ||
| 11153 | |||
| 11154 | ==== ========= ========= ============================== | ||
| 11155 | Case Target Source Write to binary log | ||
| 11156 | ==== ========= ========= ============================== | ||
| 11157 | 1 normal normal Original statement | ||
| 11158 | 2 normal temporary Generated statement | ||
| 11159 | 3 temporary normal Nothing | ||
| 11160 | 4 temporary temporary Nothing | ||
| 11161 | ==== ========= ========= ============================== | ||
| 11162 | */ | ||
| 11163 |
2/2✓ Branch 0 taken 885 times.
✓ Branch 1 taken 47 times.
|
932 | if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE)) { |
| 11164 |
2/2✓ Branch 0 taken 26 times.
✓ Branch 1 taken 859 times.
|
885 | if (src_table->table->s->tmp_table) // Case 2 |
| 11165 | { | ||
| 11166 | char buf[2048]; | ||
| 11167 | 26 | String query(buf, sizeof(buf), system_charset_info); | |
| 11168 | 26 | query.length(0); // Have to zero it since constructor doesn't | |
| 11169 |
1/2✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
|
26 | Open_table_context ot_ctx(thd, MYSQL_OPEN_REOPEN); |
| 11170 | 26 | bool new_table = false; // Whether newly created table is open. | |
| 11171 | |||
| 11172 | /* | ||
| 11173 | The condition avoids a crash as described in BUG#48506. Other | ||
| 11174 | binlogging problems related to CREATE TABLE IF NOT EXISTS LIKE | ||
| 11175 | when the existing object is a view will be solved by BUG 47442. | ||
| 11176 | */ | ||
| 11177 |
1/2✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
|
26 | if (!table->is_view()) { |
| 11178 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 2 times.
|
26 | if (!table->table) { |
| 11179 | /* | ||
| 11180 | In order for store_create_info() to work we need to open | ||
| 11181 | destination table if it is not already open (i.e. if it | ||
| 11182 | has not existed before). We don't need acquire metadata | ||
| 11183 | lock in order to do this as we already hold exclusive | ||
| 11184 | lock on this table. The table will be closed by | ||
| 11185 | close_thread_table() at the end of this branch. | ||
| 11186 | */ | ||
| 11187 |
1/2✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
|
24 | bool result = open_table(thd, table, &ot_ctx); |
| 11188 | |||
| 11189 | /* | ||
| 11190 | Play safe, ensure that we won't poison TDC/TC by storing | ||
| 11191 | not-yet-committed table definition there. | ||
| 11192 | */ | ||
| 11193 |
1/2✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
|
24 | tdc_remove_table(thd, TDC_RT_REMOVE_NOT_OWN, table->db, |
| 11194 | table->table_name, false); | ||
| 11195 | |||
| 11196 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
|
24 | if (result) goto err; |
| 11197 | 24 | new_table = true; | |
| 11198 | } | ||
| 11199 | |||
| 11200 | /* | ||
| 11201 | After opening a MERGE table add the children to the query list of | ||
| 11202 | tables, so that children tables info can be used on "CREATE TABLE" | ||
| 11203 | statement generation by the binary log. | ||
| 11204 | Note that placeholders don't have the handler open. | ||
| 11205 | */ | ||
| 11206 |
2/4✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 26 times.
|
26 | if (table->table->file->ha_extra(HA_EXTRA_ADD_CHILDREN_LIST)) { |
| 11207 | ✗ | if (new_table) { | |
| 11208 | ✗ | assert(thd->open_tables == table->table); | |
| 11209 | ✗ | close_thread_table(thd, &thd->open_tables); | |
| 11210 | ✗ | table->table = nullptr; | |
| 11211 | } | ||
| 11212 | ✗ | goto err; | |
| 11213 | } | ||
| 11214 | |||
| 11215 | /* | ||
| 11216 | As the reference table is temporary and may not exist on slave, we | ||
| 11217 | must force the ENGINE to be present into CREATE TABLE. | ||
| 11218 | */ | ||
| 11219 | 26 | create_info->used_fields |= HA_CREATE_USED_ENGINE; | |
| 11220 | |||
| 11221 |
1/2✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
|
26 | bool result [[maybe_unused]] = store_create_info( |
| 11222 | thd, table, &query, create_info, true /* show_database */, | ||
| 11223 | false /* SHOW CREATE TABLE */); | ||
| 11224 | |||
| 11225 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
|
26 | assert(result == 0); // store_create_info() always return 0 |
| 11226 | |||
| 11227 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 2 times.
|
26 | if (new_table) { |
| 11228 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
|
24 | assert(thd->open_tables == table->table); |
| 11229 | /* | ||
| 11230 | When opening the table, we ignored the locked tables | ||
| 11231 | (MYSQL_OPEN_GET_NEW_TABLE). Now we can close the table | ||
| 11232 | without risking to close some locked table. | ||
| 11233 | */ | ||
| 11234 |
1/2✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
|
24 | close_thread_table(thd, &thd->open_tables); |
| 11235 | 24 | table->table = nullptr; | |
| 11236 | } | ||
| 11237 | |||
| 11238 |
2/4✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 26 times.
|
26 | if (write_bin_log(thd, true, query.ptr(), query.length(), is_trans)) |
| 11239 | ✗ | goto err; | |
| 11240 | } | ||
| 11241 |
1/2✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
|
26 | } else // Case 1 |
| 11242 |
4/8✓ Branch 0 taken 859 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 859 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 859 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 859 times.
|
859 | if (write_bin_log(thd, true, thd->query().str, thd->query().length, |
| 11243 | is_trans)) | ||
| 11244 | ✗ | goto err; | |
| 11245 | } | ||
| 11246 | /* | ||
| 11247 | Case 3 and 4 does nothing under RBR | ||
| 11248 | */ | ||
| 11249 |
4/8✓ Branch 0 taken 209 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 209 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 209 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 209 times.
|
209 | } else if (write_bin_log(thd, true, thd->query().str, thd->query().length, |
| 11250 | is_trans)) | ||
| 11251 | ✗ | goto err; | |
| 11252 | |||
| 11253 |
2/2✓ Branch 0 taken 1068 times.
✓ Branch 1 taken 73 times.
|
1141 | if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE)) { |
| 11254 | /* | ||
| 11255 | Update the FK information for the children that were locked previously. | ||
| 11256 | */ | ||
| 11257 |
1/2✓ Branch 0 taken 1059 times.
✗ Branch 1 not taken.
|
1059 | if (!(table->table || table->is_view()) && |
| 11258 |
13/22✓ Branch 0 taken 1059 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 1059 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1059 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1059 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1059 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1059 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 1059 times.
✓ Branch 13 taken 9 times.
✓ Branch 14 taken 1059 times.
✓ Branch 15 taken 9 times.
✓ Branch 16 taken 827 times.
✓ Branch 17 taken 241 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
|
3186 | !dd::get_dictionary()->is_dd_table_name(table->db, table->table_name) && |
| 11259 |
2/2✓ Branch 0 taken 827 times.
✓ Branch 1 taken 232 times.
|
1059 | (local_create_info.db_type->flags & HTON_SUPPORTS_FOREIGN_KEYS)) { |
| 11260 | 827 | const dd::Table *new_table = nullptr; | |
| 11261 |
4/8✓ Branch 0 taken 827 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 827 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 827 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 827 times.
|
827 | if (thd->dd_client()->acquire(table->db, table->table_name, &new_table)) |
| 11262 | ✗ | goto err; | |
| 11263 | else { | ||
| 11264 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 827 times.
|
827 | assert(new_table != nullptr); |
| 11265 | /* | ||
| 11266 | If we are to support FKs for storage engines which don't support | ||
| 11267 | atomic DDL we need to decide what to do for such SEs in case of | ||
| 11268 | failure to update children definitions and adjust code accordingly. | ||
| 11269 | */ | ||
| 11270 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 827 times.
|
827 | assert(is_trans); |
| 11271 | |||
| 11272 |
1/2✓ Branch 0 taken 827 times.
✗ Branch 1 not taken.
|
827 | if (adjust_fk_children_after_parent_def_change( |
| 11273 | thd, table->db, table->table_name, local_create_info.db_type, | ||
| 11274 |
2/4✓ Branch 0 taken 827 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 827 times.
|
1654 | new_table, nullptr) || |
| 11275 |
2/4✓ Branch 0 taken 827 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 827 times.
|
827 | adjust_fk_parents(thd, table->db, table->table_name, true, nullptr)) |
| 11276 | ✗ | goto err; | |
| 11277 | } | ||
| 11278 | } | ||
| 11279 | |||
| 11280 | /* | ||
| 11281 | Update view metadata. Use nested block to ensure that TDC | ||
| 11282 | invalidation happens before commit. | ||
| 11283 | */ | ||
| 11284 | { | ||
| 11285 |
1/2✓ Branch 0 taken 1068 times.
✗ Branch 1 not taken.
|
1068 | Uncommitted_tables_guard uncommitted_tables(thd); |
| 11286 | |||
| 11287 |
5/6✓ Branch 0 taken 1059 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 1059 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1059 times.
✓ Branch 5 taken 9 times.
|
1068 | if (!table->table && !table->is_view()) |
| 11288 |
1/2✓ Branch 0 taken 1059 times.
✗ Branch 1 not taken.
|
1059 | uncommitted_tables.add_table(table); |
| 11289 | |||
| 11290 |
3/4✓ Branch 0 taken 1068 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1066 times.
|
1068 | if (update_referencing_views_metadata(thd, table, !is_trans, |
| 11291 | &uncommitted_tables)) | ||
| 11292 | 2 | goto err; | |
| 11293 |
2/2✓ Branch 0 taken 1066 times.
✓ Branch 1 taken 2 times.
|
1068 | } |
| 11294 | |||
| 11295 |
5/10✓ Branch 0 taken 1066 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1066 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1066 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1066 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 1066 times.
|
1066 | if (trans_commit_stmt(thd) || trans_commit_implicit(thd)) goto err; |
| 11296 | |||
| 11297 |
3/4✓ Branch 0 taken 825 times.
✓ Branch 1 taken 241 times.
✓ Branch 2 taken 825 times.
✗ Branch 3 not taken.
|
1066 | if (post_ddl_ht) post_ddl_ht->post_ddl(thd); |
| 11298 | } | ||
| 11299 | 1139 | return false; | |
| 11300 | |||
| 11301 | 29 | err: | |
| 11302 |
2/2✓ Branch 0 taken 26 times.
✓ Branch 1 taken 3 times.
|
29 | if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE)) { |
| 11303 |
1/2✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
|
26 | trans_rollback_stmt(thd); |
| 11304 | /* | ||
| 11305 | Full rollback in case we have THD::transaction_rollback_request | ||
| 11306 | and to synchronize DD state in cache and on disk (as statement | ||
| 11307 | rollback doesn't clear DD cache of modified uncommitted objects). | ||
| 11308 | */ | ||
| 11309 |
1/2✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
|
26 | trans_rollback(thd); |
| 11310 | |||
| 11311 |
3/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
26 | if (post_ddl_ht) post_ddl_ht->post_ddl(thd); |
| 11312 | } | ||
| 11313 | 29 | return true; | |
| 11314 | 1189 | } | |
| 11315 | |||
| 11316 | /* table_list should contain just one table */ | ||
| 11317 | 1200 | bool Sql_cmd_discard_import_tablespace::mysql_discard_or_import_tablespace( | |
| 11318 | THD *thd, TABLE_LIST *table_list) { | ||
| 11319 | 1200 | Alter_table_prelocking_strategy alter_prelocking_strategy; | |
| 11320 | int error; | ||
| 11321 |
1/2✓ Branch 0 taken 1200 times.
✗ Branch 1 not taken.
|
1200 | DBUG_TRACE; |
| 11322 | |||
| 11323 | /* | ||
| 11324 | Note that DISCARD/IMPORT TABLESPACE always is the only operation in an | ||
| 11325 | ALTER TABLE | ||
| 11326 | */ | ||
| 11327 | |||
| 11328 | /* | ||
| 11329 | DISCARD/IMPORT TABLESPACE do not respect ALGORITHM and LOCK clauses. | ||
| 11330 | */ | ||
| 11331 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1200 times.
|
1200 | if (m_alter_info->requested_lock != Alter_info::ALTER_TABLE_LOCK_DEFAULT) { |
| 11332 | ✗ | my_error(ER_ALTER_OPERATION_NOT_SUPPORTED, MYF(0), | |
| 11333 | "LOCK=NONE/SHARED/EXCLUSIVE", "LOCK=DEFAULT"); | ||
| 11334 | ✗ | return true; | |
| 11335 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1200 times.
|
1200 | } else if (m_alter_info->requested_algorithm != |
| 11336 | Alter_info::ALTER_TABLE_ALGORITHM_DEFAULT) { | ||
| 11337 | ✗ | my_error(ER_ALTER_OPERATION_NOT_SUPPORTED, MYF(0), | |
| 11338 | "ALGORITHM=COPY/INPLACE/INSTANT", "ALGORITHM=DEFAULT"); | ||
| 11339 | ✗ | return true; | |
| 11340 | } | ||
| 11341 | |||
| 11342 |
1/2✓ Branch 0 taken 1200 times.
✗ Branch 1 not taken.
|
1200 | THD_STAGE_INFO(thd, stage_discard_or_import_tablespace); |
| 11343 | |||
| 11344 | /* | ||
| 11345 | Adjust values of table-level and metadata which was set in parser | ||
| 11346 | for the case general ALTER TABLE. | ||
| 11347 | */ | ||
| 11348 | 1200 | table_list->mdl_request.set_type(MDL_EXCLUSIVE); | |
| 11349 | 1200 | table_list->set_lock({TL_WRITE, THR_DEFAULT}); | |
| 11350 | /* Do not open views. */ | ||
| 11351 | 1200 | table_list->required_type = dd::enum_table_type::BASE_TABLE; | |
| 11352 | |||
| 11353 |
2/4✓ Branch 0 taken 1200 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1200 times.
|
1200 | if (open_and_lock_tables(thd, table_list, 0, &alter_prelocking_strategy)) { |
| 11354 | /* purecov: begin inspected */ | ||
| 11355 | ✗ | return true; | |
| 11356 | /* purecov: end */ | ||
| 11357 | } | ||
| 11358 | |||
| 11359 |
2/2✓ Branch 0 taken 380 times.
✓ Branch 1 taken 820 times.
|
1200 | if (table_list->table->part_info) { |
| 11360 | /* | ||
| 11361 | If not ALL is mentioned and there is at least one specified | ||
| 11362 | [sub]partition name, use the specified [sub]partitions only. | ||
| 11363 | */ | ||
| 11364 |
2/2✓ Branch 0 taken 168 times.
✓ Branch 1 taken 212 times.
|
380 | if (m_alter_info->partition_names.elements > 0 && |
| 11365 |
1/2✓ Branch 0 taken 168 times.
✗ Branch 1 not taken.
|
168 | !(m_alter_info->flags & Alter_info::ALTER_ALL_PARTITION)) { |
| 11366 | 168 | table_list->partition_names = &m_alter_info->partition_names; | |
| 11367 | /* Set all [named] partitions as used. */ | ||
| 11368 |
3/4✓ Branch 0 taken 168 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 166 times.
|
168 | if (table_list->table->part_info->set_partition_bitmaps(table_list)) |
| 11369 | 2 | return true; | |
| 11370 | } | ||
| 11371 | } else { | ||
| 11372 |
2/2✓ Branch 0 taken 817 times.
✓ Branch 1 taken 3 times.
|
820 | if (m_alter_info->partition_names.elements > 0 || |
| 11373 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 816 times.
|
817 | m_alter_info->flags & Alter_info::ALTER_ALL_PARTITION) { |
| 11374 | /* Don't allow DISCARD/IMPORT PARTITION on a nonpartitioned table */ | ||
| 11375 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | my_error(ER_PARTITION_MGMT_ON_NONPARTITIONED, MYF(0)); |
| 11376 | 4 | return true; | |
| 11377 | } | ||
| 11378 | } | ||
| 11379 | |||
| 11380 | 1194 | bool is_non_tmp_table = (table_list->table->s->tmp_table == NO_TMP_TABLE); | |
| 11381 |
1/2✓ Branch 0 taken 1194 times.
✗ Branch 1 not taken.
|
1194 | handlerton *hton = table_list->table->s->db_type(); |
| 11382 | |||
| 11383 |
1/2✓ Branch 0 taken 1194 times.
✗ Branch 1 not taken.
|
1194 | dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client()); |
| 11384 | 1194 | dd::Table *table_def = nullptr; | |
| 11385 | |||
| 11386 |
2/2✓ Branch 0 taken 1185 times.
✓ Branch 1 taken 9 times.
|
1194 | if (is_non_tmp_table) { |
| 11387 |
4/8✓ Branch 0 taken 1185 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1185 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1185 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1185 times.
|
1185 | if (thd->dd_client()->acquire_for_modification( |
| 11388 | table_list->db, table_list->table_name, &table_def)) | ||
| 11389 | ✗ | return true; | |
| 11390 | |||
| 11391 | /* Table was successfully opened above. */ | ||
| 11392 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1185 times.
|
1185 | assert(table_def != nullptr); |
| 11393 | } else | ||
| 11394 | 9 | table_def = table_list->table->s->tmp_table_def; | |
| 11395 | |||
| 11396 | /* | ||
| 11397 | Under LOCK TABLES we need to upgrade SNRW metadata lock to X lock | ||
| 11398 | before doing discard or import of tablespace. | ||
| 11399 | |||
| 11400 | Skip this step for temporary tables as metadata locks are not | ||
| 11401 | applicable for them. | ||
| 11402 | |||
| 11403 | Remember the ticket for the future downgrade. | ||
| 11404 | */ | ||
| 11405 | 1194 | MDL_ticket *mdl_ticket = nullptr; | |
| 11406 | |||
| 11407 |
2/2✓ Branch 0 taken 1185 times.
✓ Branch 1 taken 9 times.
|
1194 | if (is_non_tmp_table && |
| 11408 |
2/2✓ Branch 0 taken 1177 times.
✓ Branch 1 taken 8 times.
|
1185 | (thd->locked_tables_mode == LTM_LOCK_TABLES || |
| 11409 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1177 times.
|
1177 | thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES)) { |
| 11410 | 8 | mdl_ticket = table_list->table->mdl_ticket; | |
| 11411 |
2/4✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
|
8 | if (thd->mdl_context.upgrade_shared_lock(mdl_ticket, MDL_EXCLUSIVE, |
| 11412 | thd->variables.lock_wait_timeout)) | ||
| 11413 | ✗ | return true; | |
| 11414 | } | ||
| 11415 | |||
| 11416 | /* | ||
| 11417 | The parser sets a flag in the Alter_info struct to indicate | ||
| 11418 | whether this is DISCARD or IMPORT. The flag is used for two purposes: | ||
| 11419 | |||
| 11420 | 1. To submit the appropriate parameter to the SE to indicate which | ||
| 11421 | operation is to be performed (see the source code below). | ||
| 11422 | 2. To implement a callback function (the plugin API function | ||
| 11423 | 'thd_tablespace_op()') allowing the SEs supporting these | ||
| 11424 | operations to check if we are doing a DISCARD or IMPORT, in order to | ||
| 11425 | suppress errors otherwise being thrown when opening tables with a | ||
| 11426 | missing tablespace. | ||
| 11427 | */ | ||
| 11428 | |||
| 11429 |
2/4✓ Branch 0 taken 1194 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1194 times.
|
1194 | if (table_list->table->has_compressed_columns()) { |
| 11430 | /* | ||
| 11431 | ALTER TABLE ... DISCARD/IMPORT TABLESPACE is not supported for tables | ||
| 11432 | with compressed columns. | ||
| 11433 | */ | ||
| 11434 | ✗ | error = HA_ERR_WRONG_COMMAND; | |
| 11435 | } else { | ||
| 11436 | 1194 | const bool discard = | |
| 11437 | 1194 | (m_alter_info->flags & Alter_info::ALTER_DISCARD_TABLESPACE); | |
| 11438 |
1/2✓ Branch 0 taken 1168 times.
✗ Branch 1 not taken.
|
1194 | error = table_list->table->file->ha_discard_or_import_tablespace(discard, |
| 11439 | table_def); | ||
| 11440 | } | ||
| 11441 | |||
| 11442 |
1/2✓ Branch 0 taken 1168 times.
✗ Branch 1 not taken.
|
1168 | THD_STAGE_INFO(thd, stage_end); |
| 11443 | |||
| 11444 |
2/2✓ Branch 0 taken 240 times.
✓ Branch 1 taken 928 times.
|
1168 | if (error) { |
| 11445 |
1/2✓ Branch 0 taken 240 times.
✗ Branch 1 not taken.
|
240 | table_list->table->file->print_error(error, MYF(0)); |
| 11446 | } else { | ||
| 11447 | // When we have imported a tablespace we need to remove any old SDIs stored | ||
| 11448 | // in it because new SDIs need not have the same keys as those found in the | ||
| 11449 | // tablspace. | ||
| 11450 |
2/2✓ Branch 0 taken 335 times.
✓ Branch 1 taken 593 times.
|
928 | if ((m_alter_info->flags & Alter_info::ALTER_IMPORT_TABLESPACE)) { |
| 11451 | // When we have imported tablespaces for individual partitions, we must | ||
| 11452 | // limit SDI removal to the tablespaces for the mentioned partitions. | ||
| 11453 |
2/2✓ Branch 0 taken 68 times.
✓ Branch 1 taken 267 times.
|
335 | if (m_alter_info->partition_names.elements > 0) { |
| 11454 |
3/10✓ Branch 0 taken 68 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 68 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 68 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
68 | DBUG_PRINT("ddsdi", ("Import partition tablespace for query:%s", |
| 11455 | thd->query().str)); | ||
| 11456 | 68 | const auto &pi = *table_list->table->part_info; | |
| 11457 | #ifndef NDEBUG | ||
| 11458 |
5/8✓ Branch 0 taken 68 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 68 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 155 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 87 times.
✓ Branch 7 taken 68 times.
|
155 | for (const auto &pn : *table_list->partition_names) { |
| 11459 |
3/8✓ Branch 0 taken 87 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 87 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 87 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
87 | DBUG_PRINT("ddsdi", ("Importing partition %s", pn.ptr())); |
| 11460 | } | ||
| 11461 | const auto &part_name_hash = | ||
| 11462 | 68 | *static_cast<Partition_share *>(table_list->table->s->ha_share) | |
| 11463 | 68 | ->partition_name_hash; | |
| 11464 | #endif /* NDEBUG */ | ||
| 11465 | 68 | uint pa_id = 0; | |
| 11466 |
3/4✓ Branch 0 taken 68 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 422 times.
✓ Branch 3 taken 68 times.
|
490 | for (const auto &lp : *table_def->leaf_partitions()) { |
| 11467 | #ifndef NDEBUG | ||
| 11468 | // Verify that part_id corresponds to index in leaf partition vector. | ||
| 11469 |
1/2✓ Branch 0 taken 422 times.
✗ Branch 1 not taken.
|
422 | auto part_def = find_or_nullptr( |
| 11470 | part_name_hash, | ||
| 11471 |
3/6✓ Branch 0 taken 422 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 422 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 422 times.
✗ Branch 5 not taken.
|
844 | std::string(lp->name().c_str(), lp->name().length())); |
| 11472 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 422 times.
|
422 | assert(part_def != nullptr); |
| 11473 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 422 times.
|
422 | assert(part_def->part_id == pa_id); |
| 11474 | #endif /* NDEBUG */ | ||
| 11475 |
3/12✓ Branch 0 taken 422 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 422 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 422 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
422 | DBUG_PRINT("ddsdi", |
| 11476 | ("Checking leaf partition %s, is_used(pa_id:%u):%s", | ||
| 11477 | lp->name().c_str(), pa_id, | ||
| 11478 | pi.is_partition_used(pa_id) ? "true" : "false")); | ||
| 11479 |
3/4✓ Branch 0 taken 93 times.
✓ Branch 1 taken 329 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 422 times.
|
515 | if (pi.is_partition_used(pa_id) && |
| 11480 |
2/4✓ Branch 0 taken 93 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 93 times.
|
93 | dd::sdi::drop_all_for_part(thd, lp)) { |
| 11481 | ✗ | error = 1; | |
| 11482 | ✗ | break; | |
| 11483 | } | ||
| 11484 | 422 | ++pa_id; | |
| 11485 | } | ||
| 11486 | } else { | ||
| 11487 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 267 times.
|
267 | assert(m_alter_info->partition_names.elements == 0); |
| 11488 | // We get here when we have imported a table tablespace, or all | ||
| 11489 | // partition tablespaces. In this case, we remove SDIs from all | ||
| 11490 | // tablespaces associated with the table. | ||
| 11491 |
2/4✓ Branch 0 taken 267 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 267 times.
|
267 | if (dd::sdi::drop_all_for_table(thd, table_def)) { |
| 11492 | ✗ | error = 1; | |
| 11493 | } | ||
| 11494 | } | ||
| 11495 | } | ||
| 11496 | |||
| 11497 | /* | ||
| 11498 | Storage engine supporting atomic DDL can fully rollback discard/ | ||
| 11499 | import if any problem occurs. This will happen during statement | ||
| 11500 | rollback. | ||
| 11501 | |||
| 11502 | In case of success we need to save dd::Table object which might | ||
| 11503 | have been updated by SE. If this step or subsequent write to binary | ||
| 11504 | log fail then statement rollback will also restore status quo ante. | ||
| 11505 | */ | ||
| 11506 |
1/2✓ Branch 0 taken 928 times.
✗ Branch 1 not taken.
|
928 | if (!error && is_non_tmp_table && |
| 11507 |
3/6✓ Branch 0 taken 928 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 928 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 928 times.
|
2784 | (hton->flags & HTON_SUPPORTS_ATOMIC_DDL) && |
| 11508 |
2/4✓ Branch 0 taken 928 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 928 times.
|
928 | thd->dd_client()->update(table_def)) |
| 11509 | ✗ | error = 1; | |
| 11510 | |||
| 11511 |
1/2✓ Branch 0 taken 928 times.
✗ Branch 1 not taken.
|
928 | if (!error) |
| 11512 |
2/4✓ Branch 0 taken 928 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 928 times.
✗ Branch 3 not taken.
|
928 | error = write_bin_log(thd, false, thd->query().str, thd->query().length, |
| 11513 |
1/2✓ Branch 0 taken 928 times.
✗ Branch 1 not taken.
|
928 | (hton->flags & HTON_SUPPORTS_ATOMIC_DDL)); |
| 11514 | |||
| 11515 | /* | ||
| 11516 | TODO: In theory since we have updated table definition in the | ||
| 11517 | data-dictionary above we need to remove its TABLE/TABLE_SHARE | ||
| 11518 | from TDC now. However this makes InnoDB to produce too many | ||
| 11519 | warnings about discarded tablespace which are not always well | ||
| 11520 | justified. So this code should be enabled after InnoDB is | ||
| 11521 | adjusted to be less verbose in these cases. | ||
| 11522 | */ | ||
| 11523 | #ifdef NEEDS_SUPPORT_FROM_INNODB | ||
| 11524 | if (is_non_tmp_table) | ||
| 11525 | close_all_tables_for_name(thd, table_list->table->s, false, nullptr); | ||
| 11526 | table_list->table = nullptr; // Safety. | ||
| 11527 | #endif | ||
| 11528 | } | ||
| 11529 | |||
| 11530 |
6/10✓ Branch 0 taken 928 times.
✓ Branch 1 taken 240 times.
✓ Branch 2 taken 928 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 928 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 928 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 928 times.
|
1168 | if (!error) error = trans_commit_stmt(thd) || trans_commit_implicit(thd); |
| 11531 | |||
| 11532 |
2/2✓ Branch 0 taken 240 times.
✓ Branch 1 taken 928 times.
|
1168 | if (error) { |
| 11533 |
1/2✓ Branch 0 taken 240 times.
✗ Branch 1 not taken.
|
240 | trans_rollback_stmt(thd); |
| 11534 |
1/2✓ Branch 0 taken 240 times.
✗ Branch 1 not taken.
|
240 | trans_rollback_implicit(thd); |
| 11535 | } | ||
| 11536 | |||
| 11537 |
4/4✓ Branch 0 taken 1159 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 1156 times.
✓ Branch 3 taken 3 times.
|
1168 | if (is_non_tmp_table && (hton->flags & HTON_SUPPORTS_ATOMIC_DDL) && |
| 11538 |
1/2✓ Branch 0 taken 1156 times.
✗ Branch 1 not taken.
|
1156 | hton->post_ddl) |
| 11539 |
1/2✓ Branch 0 taken 1156 times.
✗ Branch 1 not taken.
|
1156 | hton->post_ddl(thd); |
| 11540 | |||
| 11541 |
5/8✓ Branch 0 taken 10 times.
✓ Branch 1 taken 1158 times.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1168 times.
|
1168 | if (thd->locked_tables_mode && thd->locked_tables_list.reopen_tables(thd)) |
| 11542 | ✗ | error = 1; | |
| 11543 | |||
| 11544 |
3/4✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1160 times.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
|
1168 | if (mdl_ticket) mdl_ticket->downgrade_lock(MDL_SHARED_NO_READ_WRITE); |
| 11545 | |||
| 11546 |
2/2✓ Branch 0 taken 928 times.
✓ Branch 1 taken 240 times.
|
1168 | if (error == 0) { |
| 11547 |
1/2✓ Branch 0 taken 928 times.
✗ Branch 1 not taken.
|
928 | my_ok(thd); |
| 11548 | 928 | return false; | |
| 11549 | } | ||
| 11550 | |||
| 11551 | 240 | return true; | |
| 11552 | 1174 | } | |
| 11553 | |||
| 11554 | /** | ||
| 11555 | * Loads a table into a secondary engine if SECONDARY_LOAD, unloads from | ||
| 11556 | * secondary engine if SECONDARY_UNLOAD. | ||
| 11557 | * | ||
| 11558 | * @param thd Thread handler. | ||
| 11559 | * @param table_list Table to load. | ||
| 11560 | * | ||
| 11561 | * @return True if error, false otherwise. | ||
| 11562 | */ | ||
| 11563 | 133 | bool Sql_cmd_secondary_load_unload::mysql_secondary_load_or_unload( | |
| 11564 | THD *thd, TABLE_LIST *table_list) { | ||
| 11565 | 133 | Alter_table_prelocking_strategy alter_prelocking_strategy; | |
| 11566 | |||
| 11567 | // Because SECONDARY_LOAD and SECONDARY_UNLOAD are standalone alter table | ||
| 11568 | // actions, it should be impossible to set ALGORITHM and LOCK. | ||
| 11569 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 133 times.
|
133 | assert(m_alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_DEFAULT); |
| 11570 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 133 times.
|
133 | assert(m_alter_info->requested_algorithm == |
| 11571 | Alter_info::ALTER_TABLE_ALGORITHM_DEFAULT); | ||
| 11572 | |||
| 11573 | // Load if SECONDARY_LOAD, unload if SECONDARY_UNLOAD | ||
| 11574 | 133 | const bool is_load = m_alter_info->flags & Alter_info::ALTER_SECONDARY_LOAD; | |
| 11575 | |||
| 11576 | // SECONDARY_LOAD operation requires SNW MDL for its initial phase, which is | ||
| 11577 | // downgraded to SU lock (by RAPID SE) and eventually upgraded to X lock (by | ||
| 11578 | // SQL-layer) before updating Table Definition Cache. | ||
| 11579 | 133 | const enum_mdl_type mdl_type = | |
| 11580 |
2/2✓ Branch 0 taken 96 times.
✓ Branch 1 taken 37 times.
|
133 | is_load ? SECLOAD_SCAN_START_MDL : MDL_EXCLUSIVE; |
| 11581 | |||
| 11582 | 133 | table_list->mdl_request.set_type(mdl_type); | |
| 11583 | |||
| 11584 | // Always use isolation level READ_COMMITTED to ensure consistent view of | ||
| 11585 | // table data during entire load operation. Higher isolation levels provide no | ||
| 11586 | // benefits for this operation and could impact performance, so it's fine to | ||
| 11587 | // downgrade from both REPEATABLE_READ and SERIALIZABLE. | ||
| 11588 | 133 | const enum_tx_isolation orig_tx_isolation = thd->tx_isolation; | |
| 11589 | auto tx_isolation_guard = create_scope_guard( | ||
| 11590 |
1/2✓ Branch 0 taken 133 times.
✗ Branch 1 not taken.
|
133 | [thd, orig_tx_isolation] { thd->tx_isolation = orig_tx_isolation; }); |
| 11591 | 133 | thd->tx_isolation = ISO_READ_COMMITTED; | |
| 11592 | |||
| 11593 | // Open base table. | ||
| 11594 | 133 | table_list->required_type = dd::enum_table_type::BASE_TABLE; | |
| 11595 |
3/4✓ Branch 0 taken 133 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 131 times.
|
133 | if (open_and_lock_tables(thd, table_list, 0, &alter_prelocking_strategy)) |
| 11596 | 2 | return true; | |
| 11597 | |||
| 11598 | // SECONDARY_LOAD/SECONDARY_UNLOAD requires a secondary engine. | ||
| 11599 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 126 times.
|
131 | if (!table_list->table->s->has_secondary_engine()) { |
| 11600 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | my_error(ER_SECONDARY_ENGINE, MYF(0), "No secondary engine defined"); |
| 11601 | 5 | return true; | |
| 11602 | } | ||
| 11603 | |||
| 11604 |
6/6✓ Branch 0 taken 34 times.
✓ Branch 1 taken 92 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 32 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 124 times.
|
126 | if (!is_load && secondary_engine_lock_tables_mode(*thd)) { |
| 11605 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
2 | if (thd->mdl_context.upgrade_shared_lock(table_list->table->mdl_ticket, |
| 11606 | mdl_type, | ||
| 11607 | thd->variables.lock_wait_timeout)) | ||
| 11608 | ✗ | return true; | |
| 11609 | } | ||
| 11610 |
2/4✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 126 times.
|
126 | assert(thd->mdl_context.owns_equal_or_stronger_lock( |
| 11611 | MDL_key::TABLE, table_list->db, table_list->table_name, mdl_type)); | ||
| 11612 | |||
| 11613 | 126 | MDL_ticket *mdl_ticket = table_list->table->mdl_ticket; | |
| 11614 | 130 | auto downgrade_guard = create_scope_guard([mdl_ticket, thd] { | |
| 11615 | // Under LOCK TABLES, downgrade to MDL_SHARED_NO_READ_WRITE after all | ||
| 11616 | // operations have completed. | ||
| 11617 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 122 times.
|
126 | if (secondary_engine_lock_tables_mode(*thd)) { |
| 11618 | 4 | mdl_ticket->downgrade_lock(MDL_SHARED_NO_READ_WRITE); | |
| 11619 | } | ||
| 11620 |
1/2✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
|
126 | }); |
| 11621 | |||
| 11622 | // Omit hidden generated columns and columns marked as NOT SECONDARY from | ||
| 11623 | // read_set. It is the responsibility of the secondary engine handler to load | ||
| 11624 | // only the columns included in the read_set. | ||
| 11625 | 126 | bitmap_clear_all(table_list->table->read_set); | |
| 11626 |
2/2✓ Branch 0 taken 318 times.
✓ Branch 1 taken 126 times.
|
444 | for (Field **field = table_list->table->field; *field != nullptr; ++field) { |
| 11627 | // Skip hidden generated columns. | ||
| 11628 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 317 times.
|
318 | if (bitmap_is_set(&table_list->table->fields_for_functional_indexes, |
| 11629 | 318 | (*field)->field_index())) | |
| 11630 | 1 | continue; | |
| 11631 | |||
| 11632 | // Skip columns marked as NOT SECONDARY. | ||
| 11633 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 306 times.
|
317 | if ((*field)->is_flag_set(NOT_SECONDARY_FLAG)) continue; |
| 11634 | |||
| 11635 | // Mark column as eligible for loading. | ||
| 11636 |
1/2✓ Branch 0 taken 306 times.
✗ Branch 1 not taken.
|
306 | table_list->table->mark_column_used(*field, MARK_COLUMNS_READ); |
| 11637 | } | ||
| 11638 | |||
| 11639 | // It should not have been possible to define a temporary table with a | ||
| 11640 | // secondary engine. | ||
| 11641 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
|
126 | assert(table_list->table->s->tmp_table == NO_TMP_TABLE); |
| 11642 | |||
| 11643 |
1/2✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
|
126 | handlerton *hton = table_list->table->s->db_type(); |
| 11644 |
3/6✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 126 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 126 times.
✗ Branch 5 not taken.
|
126 | assert(hton->flags & HTON_SUPPORTS_ATOMIC_DDL && |
| 11645 | hton->flags & HTON_SUPPORTS_SECONDARY_ENGINE && | ||
| 11646 | hton->post_ddl != nullptr); | ||
| 11647 | |||
| 11648 |
1/2✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
|
126 | dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client()); |
| 11649 | 126 | dd::Table *table_def = nullptr; | |
| 11650 |
4/8✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 126 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 126 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 126 times.
|
126 | if (thd->dd_client()->acquire_for_modification( |
| 11651 | table_list->db, table_list->table_name, &table_def)) | ||
| 11652 | ✗ | return true; | |
| 11653 | |||
| 11654 | // Cleanup that must be done regardless of commit or rollback. | ||
| 11655 | 256 | auto cleanup = [thd, hton]() { | |
| 11656 | 126 | hton->post_ddl(thd); | |
| 11657 | |||
| 11658 | // reopen_tables() will only affect tables which have been closed by | ||
| 11659 | // close_all_tables_for_name(), which means it will do reopen only while we | ||
| 11660 | // hold X lock on table. | ||
| 11661 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 122 times.
|
130 | return thd->locked_tables_mode && |
| 11662 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
130 | thd->locked_tables_list.reopen_tables(thd); |
| 11663 | 126 | }; | |
| 11664 | |||
| 11665 | // This scope guard is responsible for rolling back the transaction in case of | ||
| 11666 | // any errors. | ||
| 11667 | 12 | auto rollback_guard = create_scope_guard([thd, cleanup] { | |
| 11668 | 6 | trans_rollback_stmt(thd); | |
| 11669 | 6 | trans_rollback_implicit(thd); | |
| 11670 | 6 | cleanup(); | |
| 11671 |
1/2✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
|
126 | }); |
| 11672 | |||
| 11673 |
2/2✓ Branch 0 taken 92 times.
✓ Branch 1 taken 34 times.
|
126 | if (is_load) { |
| 11674 |
2/4✓ Branch 0 taken 92 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
93 | if (DBUG_EVALUATE_IF("sim_secload_fail", |
| 11675 | (my_error(ER_SECONDARY_ENGINE, MYF(0), | ||
| 11676 | "Simulated failure of secondary_load()"), | ||
| 11677 | true), | ||
| 11678 |
4/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 91 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 87 times.
|
184 | false) || |
| 11679 |
3/4✓ Branch 0 taken 91 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 87 times.
|
91 | secondary_engine_load_table(thd, *table_list->table)) |
| 11680 | 5 | return true; | |
| 11681 | } else { | ||
| 11682 |
2/4✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
35 | if (DBUG_EVALUATE_IF("sim_secunload_fail", |
| 11683 | (my_error(ER_SECONDARY_ENGINE, MYF(0), | ||
| 11684 | "Simulated failure of secondary_unload()"), | ||
| 11685 | true), | ||
| 11686 |
4/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 33 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 33 times.
|
68 | false) || |
| 11687 |
2/4✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 33 times.
|
33 | secondary_engine_unload_table(thd, table_list->db, |
| 11688 | table_list->table_name, *table_def, true)) | ||
| 11689 | 1 | return true; | |
| 11690 | } | ||
| 11691 | |||
| 11692 | // Need to upgrade to allow old table definition to be purged from TDC | ||
| 11693 | // (this is no-op in case of SECONDARY_UNLOAD). | ||
| 11694 |
2/4✓ Branch 0 taken 120 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 120 times.
✗ Branch 3 not taken.
|
120 | DEBUG_SYNC(thd, "secload_upgrade_mdl_x"); |
| 11695 |
2/4✓ Branch 0 taken 120 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 120 times.
|
120 | if (thd->mdl_context.upgrade_shared_lock(mdl_ticket, SECLOAD_TDC_EVICT_MDL, |
| 11696 | thd->variables.lock_wait_timeout)) | ||
| 11697 | ✗ | return true; | |
| 11698 | |||
| 11699 | // Update the secondary_load flag based on the current operation. | ||
| 11700 |
6/14✓ Branch 0 taken 120 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 120 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 120 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 120 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 120 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 120 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
|
240 | if (table_def->options().set("secondary_load", is_load) || |
| 11701 |
2/4✓ Branch 0 taken 120 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 120 times.
|
120 | thd->dd_client()->update(table_def)) |
| 11702 | ✗ | return true; | |
| 11703 | |||
| 11704 | // Close primary table. | ||
| 11705 |
1/2✓ Branch 0 taken 120 times.
✗ Branch 1 not taken.
|
120 | close_all_tables_for_name(thd, table_list->table->s, false, nullptr); |
| 11706 | 120 | table_list->table = nullptr; | |
| 11707 | |||
| 11708 | // Commit transaction if no errors. | ||
| 11709 |
5/10✓ Branch 0 taken 120 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 120 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 120 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 120 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 120 times.
|
120 | if (trans_commit_stmt(thd) || trans_commit_implicit(thd)) return true; |
| 11710 | |||
| 11711 | // Transaction committed successfully, no rollback will be necessary. | ||
| 11712 | 120 | rollback_guard.commit(); | |
| 11713 | |||
| 11714 |
2/4✓ Branch 0 taken 120 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 120 times.
|
120 | if (cleanup()) return true; |
| 11715 | |||
| 11716 |
1/2✓ Branch 0 taken 120 times.
✗ Branch 1 not taken.
|
120 | my_ok(thd); |
| 11717 | 120 | return false; | |
| 11718 | 133 | } | |
| 11719 | |||
| 11720 | /** | ||
| 11721 | Check if key is a candidate key, i.e. a unique index with no index | ||
| 11722 | fields partial, nullable or virtual generated. | ||
| 11723 | */ | ||
| 11724 | |||
| 11725 | 34417 | static bool is_candidate_key(KEY *key) { | |
| 11726 | KEY_PART_INFO *key_part; | ||
| 11727 | 34417 | KEY_PART_INFO *key_part_end = key->key_part + key->user_defined_key_parts; | |
| 11728 | |||
| 11729 |
4/4✓ Branch 0 taken 14074 times.
✓ Branch 1 taken 20343 times.
✓ Branch 2 taken 10991 times.
✓ Branch 3 taken 3083 times.
|
34417 | if (!(key->flags & HA_NOSAME) || (key->flags & HA_NULL_PART_KEY)) |
| 11730 | 31334 | return false; | |
| 11731 | |||
| 11732 |
2/2✓ Branch 0 taken 154 times.
✓ Branch 1 taken 2929 times.
|
3083 | if (key->flags & HA_VIRTUAL_GEN_KEY) return false; |
| 11733 | |||
| 11734 |
2/2✓ Branch 0 taken 2997 times.
✓ Branch 1 taken 2920 times.
|
5917 | for (key_part = key->key_part; key_part < key_part_end; key_part++) { |
| 11735 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 2988 times.
|
2997 | if (key_part->key_part_flag & HA_PART_KEY_SEG) return false; |
| 11736 | } | ||
| 11737 | |||
| 11738 | 2920 | return true; | |
| 11739 | } | ||
| 11740 | |||
| 11741 | /** | ||
| 11742 | Get Create_field object for newly created table by field index. | ||
| 11743 | |||
| 11744 | @param alter_info Alter_info describing newly created table. | ||
| 11745 | @param idx Field index. | ||
| 11746 | */ | ||
| 11747 | |||
| 11748 | 2072259 | static const Create_field *get_field_by_index(Alter_info *alter_info, | |
| 11749 | uint idx) { | ||
| 11750 |
1/2✓ Branch 0 taken 2072259 times.
✗ Branch 1 not taken.
|
2072259 | List_iterator_fast<Create_field> field_it(alter_info->create_list); |
| 11751 | 2072259 | uint field_idx = 0; | |
| 11752 | const Create_field *field; | ||
| 11753 | |||
| 11754 |
5/6✓ Branch 0 taken 11878920 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9806661 times.
✓ Branch 3 taken 2072259 times.
✓ Branch 4 taken 9806661 times.
✓ Branch 5 taken 2072259 times.
|
11878920 | while ((field = field_it++) && field_idx < idx) { |
| 11755 | 9806661 | field_idx++; | |
| 11756 | } | ||
| 11757 | |||
| 11758 | 2072259 | return field; | |
| 11759 | } | ||
| 11760 | |||
| 11761 | /** | ||
| 11762 | Look-up KEY object by index name using case-insensitive comparison. | ||
| 11763 | |||
| 11764 | @param key_name Index name. | ||
| 11765 | @param key_start Start of array of KEYs for table. | ||
| 11766 | @param key_end End of array of KEYs for table. | ||
| 11767 | |||
| 11768 | @note Skips indexes which are marked as renamed. | ||
| 11769 | @note Case-insensitive comparison is necessary to correctly | ||
| 11770 | handle renaming of keys. | ||
| 11771 | |||
| 11772 | @retval non-NULL - pointer to KEY object for index found. | ||
| 11773 | @retval NULL - no index with such name found (or it is marked | ||
| 11774 | as renamed). | ||
| 11775 | */ | ||
| 11776 | |||
| 11777 | 430 | static KEY *find_key_ci(const char *key_name, KEY *key_start, KEY *key_end) { | |
| 11778 |
2/2✓ Branch 0 taken 702 times.
✓ Branch 1 taken 2 times.
|
704 | for (KEY *key = key_start; key < key_end; key++) { |
| 11779 | /* Skip already renamed keys. */ | ||
| 11780 |
4/4✓ Branch 0 taken 700 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 428 times.
✓ Branch 3 taken 274 times.
|
1402 | if (!(key->flags & HA_KEY_RENAMED) && |
| 11781 |
2/2✓ Branch 0 taken 428 times.
✓ Branch 1 taken 272 times.
|
700 | !my_strcasecmp(system_charset_info, key_name, key->name)) |
| 11782 | 428 | return key; | |
| 11783 | } | ||
| 11784 | 2 | return nullptr; | |
| 11785 | } | ||
| 11786 | |||
| 11787 | /** | ||
| 11788 | Look-up KEY object by index name using case-sensitive comparison. | ||
| 11789 | |||
| 11790 | @param key_name Index name. | ||
| 11791 | @param key_start Start of array of KEYs for table. | ||
| 11792 | @param key_end End of array of KEYs for table. | ||
| 11793 | |||
| 11794 | @note Skips indexes which are marked as renamed. | ||
| 11795 | @note Case-sensitive comparison is necessary to correctly | ||
| 11796 | handle: ALTER TABLE t1 DROP KEY x, ADD KEY X(c). | ||
| 11797 | where new and old index are identical except case | ||
| 11798 | of their names (in this case index still needs | ||
| 11799 | to be re-created to keep case of the name in .FRM | ||
| 11800 | and storage-engine in sync). | ||
| 11801 | |||
| 11802 | @retval non-NULL - pointer to KEY object for index found. | ||
| 11803 | @retval NULL - no index with such name found (or it is marked | ||
| 11804 | as renamed). | ||
| 11805 | */ | ||
| 11806 | |||
| 11807 | 163612 | static KEY *find_key_cs(const char *key_name, KEY *key_start, KEY *key_end) { | |
| 11808 |
2/2✓ Branch 0 taken 231073 times.
✓ Branch 1 taken 18404 times.
|
249477 | for (KEY *key = key_start; key < key_end; key++) { |
| 11809 | /* Skip renamed keys. */ | ||
| 11810 |
4/4✓ Branch 0 taken 230932 times.
✓ Branch 1 taken 141 times.
✓ Branch 2 taken 145208 times.
✓ Branch 3 taken 85724 times.
|
231073 | if (!(key->flags & HA_KEY_RENAMED) && !strcmp(key_name, key->name)) |
| 11811 | 145208 | return key; | |
| 11812 | } | ||
| 11813 | 18404 | return nullptr; | |
| 11814 | } | ||
| 11815 | |||
| 11816 | /** | ||
| 11817 | Check if index has changed in a new version of table (ignore | ||
| 11818 | possible rename of index). Also changes to the comment field | ||
| 11819 | of the key is marked with a flag in the ha_alter_info. | ||
| 11820 | |||
| 11821 | @param[in,out] ha_alter_info Structure describing changes to be done | ||
| 11822 | by ALTER TABLE and holding data used | ||
| 11823 | during in-place alter. | ||
| 11824 | @param table_key Description of key in old version of table. | ||
| 11825 | @param new_key Description of key in new version of table. | ||
| 11826 | |||
| 11827 | @returns True - if index has changed, false -otherwise. | ||
| 11828 | */ | ||
| 11829 | |||
| 11830 | 72719 | static bool has_index_def_changed(Alter_inplace_info *ha_alter_info, | |
| 11831 | const KEY *table_key, const KEY *new_key) { | ||
| 11832 | const KEY_PART_INFO *key_part, *new_part, *end; | ||
| 11833 | const Create_field *new_field; | ||
| 11834 | 72719 | Alter_info *alter_info = ha_alter_info->alter_info; | |
| 11835 | |||
| 11836 | /* Check that the key types are compatible between old and new tables. */ | ||
| 11837 |
2/2✓ Branch 0 taken 72718 times.
✓ Branch 1 taken 1 times.
|
72719 | if ((table_key->algorithm != new_key->algorithm) || |
| 11838 | 72718 | ((table_key->flags & HA_KEYFLAG_MASK) != | |
| 11839 |
2/2✓ Branch 0 taken 72681 times.
✓ Branch 1 taken 37 times.
|
72718 | (new_key->flags & HA_KEYFLAG_MASK)) || |
| 11840 |
2/2✓ Branch 0 taken 153 times.
✓ Branch 1 taken 72528 times.
|
72681 | (table_key->user_defined_key_parts != new_key->user_defined_key_parts)) |
| 11841 | 191 | return true; | |
| 11842 | |||
| 11843 | /* | ||
| 11844 | If an index comment is added/dropped/changed, then mark it for a | ||
| 11845 | fast/INPLACE alteration. | ||
| 11846 | */ | ||
| 11847 |
2/2✓ Branch 0 taken 72519 times.
✓ Branch 1 taken 9 times.
|
72528 | if ((table_key->comment.length != new_key->comment.length) || |
| 11848 |
2/2✓ Branch 0 taken 231 times.
✓ Branch 1 taken 72288 times.
|
72519 | (table_key->comment.length && |
| 11849 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 227 times.
|
231 | strcmp(table_key->comment.str, new_key->comment.str))) |
| 11850 | 13 | ha_alter_info->handler_flags |= Alter_inplace_info::ALTER_INDEX_COMMENT; | |
| 11851 | |||
| 11852 | /* | ||
| 11853 | Check that the key parts remain compatible between the old and | ||
| 11854 | new tables. | ||
| 11855 | */ | ||
| 11856 | 72528 | end = table_key->key_part + table_key->user_defined_key_parts; | |
| 11857 | 72528 | for (key_part = table_key->key_part, new_part = new_key->key_part; | |
| 11858 |
2/2✓ Branch 0 taken 113394 times.
✓ Branch 1 taken 70019 times.
|
183413 | key_part < end; key_part++, new_part++) { |
| 11859 | 113394 | new_field = get_field_by_index(alter_info, new_part->fieldnr); | |
| 11860 | |||
| 11861 | /* | ||
| 11862 | If there is a change in index length due to column expansion | ||
| 11863 | like varchar(X) changed to varchar(X + N) and has a compatible | ||
| 11864 | packed data representation, we mark it for fast/INPLACE change | ||
| 11865 | in index definition. Some engines like InnoDB supports INPLACE | ||
| 11866 | alter for such cases. | ||
| 11867 | |||
| 11868 | In other cases, key definition has changed if we are using a | ||
| 11869 | different field or if the used key part length is different, or | ||
| 11870 | key part direction has changed. | ||
| 11871 | */ | ||
| 11872 | 229202 | if (key_part->length != new_part->length && | |
| 11873 |
6/6✓ Branch 0 taken 2414 times.
✓ Branch 1 taken 110980 times.
✓ Branch 2 taken 1441 times.
✓ Branch 3 taken 973 times.
✓ Branch 4 taken 16 times.
✓ Branch 5 taken 113378 times.
|
114835 | ha_alter_info->alter_info->flags == Alter_info::ALTER_CHANGE_COLUMN && |
| 11874 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 1425 times.
|
1441 | (key_part->field->is_equal(new_field) == IS_EQUAL_PACK_LENGTH)) { |
| 11875 | 16 | ha_alter_info->handler_flags |= | |
| 11876 | Alter_inplace_info::ALTER_COLUMN_INDEX_LENGTH; | ||
| 11877 |
2/2✓ Branch 0 taken 2398 times.
✓ Branch 1 taken 110980 times.
|
113378 | } else if (key_part->length != new_part->length) |
| 11878 | 2398 | return true; | |
| 11879 | |||
| 11880 | 110996 | if ((key_part->key_part_flag & HA_REVERSE_SORT) != | |
| 11881 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 110984 times.
|
110996 | (new_part->key_part_flag & HA_REVERSE_SORT)) |
| 11882 | 12 | return true; | |
| 11883 | |||
| 11884 | /* | ||
| 11885 | For prefix keys KEY_PART_INFO::field points to cloned Field | ||
| 11886 | object with adjusted length. So below we have to check field | ||
| 11887 | indexes instead of simply comparing pointers to Field objects. | ||
| 11888 | */ | ||
| 11889 |
4/4✓ Branch 0 taken 110958 times.
✓ Branch 1 taken 26 times.
✓ Branch 2 taken 96 times.
✓ Branch 3 taken 110888 times.
|
221942 | if (!new_field->field || |
| 11890 |
2/2✓ Branch 0 taken 70 times.
✓ Branch 1 taken 110888 times.
|
110958 | new_field->field->field_index() != key_part->fieldnr - 1) |
| 11891 | 96 | return true; | |
| 11892 | |||
| 11893 | /* | ||
| 11894 | Key definition has changed, if the key is converted from a | ||
| 11895 | non-prefixed key to a prefixed key or vice-versa. This | ||
| 11896 | is because InnoDB treats prefix keys differently from | ||
| 11897 | full-column keys. Ignoring BLOBs since the key_length() | ||
| 11898 | is not set correctly and also the prefix is ignored | ||
| 11899 | for FULLTEXT keys. | ||
| 11900 | Ex: When the column length is increased but the key part | ||
| 11901 | length remains the same. | ||
| 11902 | */ | ||
| 11903 |
2/2✓ Branch 0 taken 107652 times.
✓ Branch 1 taken 3236 times.
|
110888 | if (!(new_field->flags & BLOB_FLAG) && |
| 11904 |
2/2✓ Branch 0 taken 106625 times.
✓ Branch 1 taken 1027 times.
|
107652 | (table_key->algorithm != HA_KEY_ALG_FULLTEXT)) { |
| 11905 | 106625 | bool old_part_key_seg = (key_part->key_part_flag & HA_PART_KEY_SEG); | |
| 11906 | 106625 | bool new_part_key_seg = (new_field->key_length() != new_part->length); | |
| 11907 | |||
| 11908 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 106622 times.
|
106625 | if (old_part_key_seg ^ new_part_key_seg) return true; |
| 11909 | } | ||
| 11910 | } | ||
| 11911 | |||
| 11912 | 70019 | return false; | |
| 11913 | } | ||
| 11914 | |||
| 11915 | /** | ||
| 11916 | Compare original and new versions of a table and fill Alter_inplace_info | ||
| 11917 | describing differences between those versions. | ||
| 11918 | |||
| 11919 | @param thd Thread | ||
| 11920 | @param table The original table. | ||
| 11921 | @param[in,out] ha_alter_info Data structure which already contains | ||
| 11922 | basic information about create options, | ||
| 11923 | field and keys for the new version of | ||
| 11924 | table and which should be completed with | ||
| 11925 | more detailed information needed for | ||
| 11926 | in-place ALTER. | ||
| 11927 | |||
| 11928 | First argument 'table' contains information of the original | ||
| 11929 | table, which includes all corresponding parts that the new | ||
| 11930 | table has in arguments create_list, key_list and create_info. | ||
| 11931 | |||
| 11932 | Compare the changes between the original and new table definitions. | ||
| 11933 | The result of this comparison is then passed to SE which determines | ||
| 11934 | whether it can carry out these changes in-place. | ||
| 11935 | |||
| 11936 | Mark any changes detected in the ha_alter_flags. | ||
| 11937 | We generally try to specify handler flags only if there are real | ||
| 11938 | changes. But in cases when it is cumbersome to determine if some | ||
| 11939 | attribute has really changed we might choose to set flag | ||
| 11940 | pessimistically, for example, relying on parser output only. | ||
| 11941 | |||
| 11942 | If there are no data changes, but index changes, 'index_drop_buffer' | ||
| 11943 | and/or 'index_add_buffer' are populated with offsets into | ||
| 11944 | table->key_info or key_info_buffer respectively for the indexes | ||
| 11945 | that need to be dropped and/or (re-)created. | ||
| 11946 | |||
| 11947 | Note that this function assumes that it is OK to change Alter_info | ||
| 11948 | and HA_CREATE_INFO which it gets. It is caller who is responsible | ||
| 11949 | for creating copies for this structures if he needs them unchanged. | ||
| 11950 | |||
| 11951 | @retval true error | ||
| 11952 | @retval false success | ||
| 11953 | */ | ||
| 11954 | |||
| 11955 | 74915 | static bool fill_alter_inplace_info(THD *thd, TABLE *table, | |
| 11956 | Alter_inplace_info *ha_alter_info) { | ||
| 11957 | Field **f_ptr, *field; | ||
| 11958 | 74915 | List_iterator_fast<Create_field> new_field_it; | |
| 11959 | Create_field *new_field; | ||
| 11960 | 74915 | uint candidate_key_count = 0; | |
| 11961 | 74915 | Alter_info *alter_info = ha_alter_info->alter_info; | |
| 11962 | 74915 | Prealloced_array<Field *, 1> gcols_with_unchanged_expr(PSI_INSTRUMENT_ME); | |
| 11963 | // Names of columns which default might have changed. | ||
| 11964 | 74915 | Prealloced_array<const char *, 1> cols_with_default_change(PSI_INSTRUMENT_ME); | |
| 11965 | // Old table version columns which were renamed or dropped. | ||
| 11966 | 74915 | Prealloced_array<const Field *, 1> dropped_or_renamed_cols(PSI_INSTRUMENT_ME); | |
| 11967 |
1/2✓ Branch 0 taken 74915 times.
✗ Branch 1 not taken.
|
74915 | DBUG_TRACE; |
| 11968 | |||
| 11969 | /* Allocate result buffers. */ | ||
| 11970 | 149830 | if (!(ha_alter_info->index_drop_buffer = | |
| 11971 |
1/2✓ Branch 0 taken 74915 times.
✗ Branch 1 not taken.
|
74915 | (KEY **)thd->alloc(sizeof(KEY *) * table->s->keys)) || |
| 11972 | 74915 | !(ha_alter_info->index_add_buffer = | |
| 11973 |
2/4✓ Branch 0 taken 74915 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 74915 times.
✗ Branch 3 not taken.
|
74915 | (uint *)thd->alloc(sizeof(uint) * alter_info->key_list.size())) || |
| 11974 |
2/4✓ Branch 0 taken 74915 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 74915 times.
✗ Branch 3 not taken.
|
74915 | !(ha_alter_info->index_rename_buffer = (KEY_PAIR *)thd->alloc( |
| 11975 |
2/4✓ Branch 0 taken 74915 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 74915 times.
|
224745 | sizeof(KEY_PAIR) * alter_info->alter_rename_key_list.size())) || |
| 11976 |
2/4✓ Branch 0 taken 74915 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 74915 times.
|
74915 | !(ha_alter_info->index_altered_visibility_buffer = (KEY_PAIR *)thd->alloc( |
| 11977 | 74915 | sizeof(KEY_PAIR) * alter_info->alter_index_visibility_list.size()))) | |
| 11978 | ✗ | return true; | |
| 11979 | |||
| 11980 | /* First we setup ha_alter_flags based on what was detected by parser. */ | ||
| 11981 | |||
| 11982 | /* | ||
| 11983 | Comparing new and old default values of column is cumbersome. | ||
| 11984 | So instead of using such a comparison for detecting if default | ||
| 11985 | has really changed we rely on flags set by parser to get an | ||
| 11986 | approximate value for storage engine flag. | ||
| 11987 | */ | ||
| 11988 |
2/2✓ Branch 0 taken 17140 times.
✓ Branch 1 taken 57775 times.
|
74915 | if (alter_info->flags & (Alter_info::ALTER_CHANGE_COLUMN | |
| 11989 | Alter_info::ALTER_CHANGE_COLUMN_DEFAULT)) | ||
| 11990 | 17140 | ha_alter_info->handler_flags |= Alter_inplace_info::ALTER_COLUMN_DEFAULT; | |
| 11991 |
2/2✓ Branch 0 taken 181 times.
✓ Branch 1 taken 74734 times.
|
74915 | if (alter_info->flags & Alter_info::ADD_FOREIGN_KEY) |
| 11992 | 181 | ha_alter_info->handler_flags |= Alter_inplace_info::ADD_FOREIGN_KEY; | |
| 11993 |
2/2✓ Branch 0 taken 57 times.
✓ Branch 1 taken 74858 times.
|
74915 | if (alter_info->flags & Alter_info::DROP_FOREIGN_KEY) |
| 11994 | 57 | ha_alter_info->handler_flags |= Alter_inplace_info::DROP_FOREIGN_KEY; | |
| 11995 |
2/2✓ Branch 0 taken 27166 times.
✓ Branch 1 taken 47749 times.
|
74915 | if (alter_info->flags & Alter_info::ALTER_OPTIONS) |
| 11996 | 27166 | ha_alter_info->handler_flags |= Alter_inplace_info::CHANGE_CREATE_OPTION; | |
| 11997 |
2/2✓ Branch 0 taken 259 times.
✓ Branch 1 taken 74656 times.
|
74915 | if (alter_info->flags & Alter_info::ALTER_RENAME) |
| 11998 | 259 | ha_alter_info->handler_flags |= Alter_inplace_info::ALTER_RENAME; | |
| 11999 | /* Check partition changes */ | ||
| 12000 |
2/2✓ Branch 0 taken 286 times.
✓ Branch 1 taken 74629 times.
|
74915 | if (alter_info->flags & Alter_info::ALTER_ADD_PARTITION) |
| 12001 | 286 | ha_alter_info->handler_flags |= Alter_inplace_info::ADD_PARTITION; | |
| 12002 |
2/2✓ Branch 0 taken 286 times.
✓ Branch 1 taken 74629 times.
|
74915 | if (alter_info->flags & Alter_info::ALTER_DROP_PARTITION) |
| 12003 | 286 | ha_alter_info->handler_flags |= Alter_inplace_info::DROP_PARTITION; | |
| 12004 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 74915 times.
|
74915 | if (alter_info->flags & Alter_info::ALTER_PARTITION) |
| 12005 | ✗ | ha_alter_info->handler_flags |= Alter_inplace_info::ALTER_PARTITION; | |
| 12006 |
2/2✓ Branch 0 taken 155 times.
✓ Branch 1 taken 74760 times.
|
74915 | if (alter_info->flags & Alter_info::ALTER_COALESCE_PARTITION) |
| 12007 | 155 | ha_alter_info->handler_flags |= Alter_inplace_info::COALESCE_PARTITION; | |
| 12008 |
2/2✓ Branch 0 taken 228 times.
✓ Branch 1 taken 74687 times.
|
74915 | if (alter_info->flags & Alter_info::ALTER_REORGANIZE_PARTITION) |
| 12009 | 228 | ha_alter_info->handler_flags |= Alter_inplace_info::REORGANIZE_PARTITION; | |
| 12010 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 74914 times.
|
74915 | if (alter_info->flags & Alter_info::ALTER_TABLE_REORG) |
| 12011 | 1 | ha_alter_info->handler_flags |= Alter_inplace_info::ALTER_TABLE_REORG; | |
| 12012 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 74915 times.
|
74915 | if (alter_info->flags & Alter_info::ALTER_REMOVE_PARTITIONING) |
| 12013 | ✗ | ha_alter_info->handler_flags |= | |
| 12014 | Alter_inplace_info::ALTER_REMOVE_PARTITIONING; | ||
| 12015 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 74909 times.
|
74915 | if (alter_info->flags & Alter_info::ALTER_ALL_PARTITION) |
| 12016 | 6 | ha_alter_info->handler_flags |= Alter_inplace_info::ALTER_ALL_PARTITION; | |
| 12017 |
2/2✓ Branch 0 taken 114 times.
✓ Branch 1 taken 74801 times.
|
74915 | if (alter_info->flags & Alter_info::ALTER_REBUILD_PARTITION) |
| 12018 | 114 | ha_alter_info->handler_flags |= | |
| 12019 | Alter_inplace_info::ALTER_REBUILD_PARTITION; /* purecov: deadcode */ | ||
| 12020 | /* Check for: ALTER TABLE FORCE, ALTER TABLE ENGINE and OPTIMIZE TABLE. */ | ||
| 12021 |
2/2✓ Branch 0 taken 5192 times.
✓ Branch 1 taken 69723 times.
|
74915 | if (alter_info->flags & Alter_info::ALTER_RECREATE) |
| 12022 | 5192 | ha_alter_info->handler_flags |= Alter_inplace_info::RECREATE_TABLE; | |
| 12023 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 74901 times.
|
74915 | if (alter_info->with_validation == Alter_info::ALTER_WITH_VALIDATION) |
| 12024 | 14 | ha_alter_info->handler_flags |= Alter_inplace_info::VALIDATE_VIRTUAL_COLUMN; | |
| 12025 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 74904 times.
|
74915 | if (alter_info->flags & Alter_info::ADD_CHECK_CONSTRAINT) |
| 12026 | 11 | ha_alter_info->handler_flags |= Alter_inplace_info::ADD_CHECK_CONSTRAINT; | |
| 12027 |
2/2✓ Branch 0 taken 28 times.
✓ Branch 1 taken 74887 times.
|
74915 | if (alter_info->flags & Alter_info::DROP_CHECK_CONSTRAINT) |
| 12028 | 28 | ha_alter_info->handler_flags |= Alter_inplace_info::DROP_CHECK_CONSTRAINT; | |
| 12029 |
2/2✓ Branch 0 taken 112 times.
✓ Branch 1 taken 74803 times.
|
74915 | if (alter_info->flags & Alter_info::SUSPEND_CHECK_CONSTRAINT) |
| 12030 | 112 | ha_alter_info->handler_flags |= | |
| 12031 | Alter_inplace_info::SUSPEND_CHECK_CONSTRAINT; | ||
| 12032 |
2/2✓ Branch 0 taken 17 times.
✓ Branch 1 taken 74898 times.
|
74915 | if (alter_info->flags & Alter_info::ALTER_COLUMN_VISIBILITY) |
| 12033 | 17 | ha_alter_info->handler_flags |= Alter_inplace_info::ALTER_COLUMN_VISIBILITY; | |
| 12034 | |||
| 12035 | /* | ||
| 12036 | Go through fields in old version of table and detect changes to them. | ||
| 12037 | We don't want to rely solely on Alter_info flags for this since: | ||
| 12038 | a) new definition of column can be fully identical to the old one | ||
| 12039 | despite the fact that this column is mentioned in MODIFY clause. | ||
| 12040 | b) even if new column type differs from its old column from metadata | ||
| 12041 | point of view, it might be identical from storage engine point | ||
| 12042 | of view (e.g. when ENUM('a','b') is changed to ENUM('a','b',c')). | ||
| 12043 | c) flags passed to storage engine contain more detailed information | ||
| 12044 | about nature of changes than those provided from parser. | ||
| 12045 | */ | ||
| 12046 | 74915 | uint old_field_index_without_vgc = 0; | |
| 12047 |
2/2✓ Branch 0 taken 653683 times.
✓ Branch 1 taken 74915 times.
|
728598 | for (f_ptr = table->field; (field = *f_ptr); f_ptr++) { |
| 12048 |
5/8✓ Branch 0 taken 653683 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 653683 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 653681 times.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
|
653683 | DBUG_PRINT("inplace", ("Existing field: %s", field->field_name)); |
| 12049 | |||
| 12050 | /* Clear marker for renamed or dropped field | ||
| 12051 | which we are going to set later. */ | ||
| 12052 | 653683 | field->clear_flag(FIELD_IS_RENAMED); | |
| 12053 | 653683 | field->clear_flag(FIELD_IS_DROPPED); | |
| 12054 | |||
| 12055 | /* Use transformed info to evaluate flags for storage engine. */ | ||
| 12056 | 653683 | uint new_field_index = 0; | |
| 12057 | 653683 | uint new_field_index_without_vgc = 0; | |
| 12058 | 653683 | new_field_it.init(alter_info->create_list); | |
| 12059 |
2/2✓ Branch 0 taken 14885957 times.
✓ Branch 1 taken 2558 times.
|
14888515 | while ((new_field = new_field_it++)) { |
| 12060 |
2/2✓ Branch 0 taken 651125 times.
✓ Branch 1 taken 14234832 times.
|
14885957 | if (new_field->field == field) break; |
| 12061 |
2/2✓ Branch 0 taken 14076665 times.
✓ Branch 1 taken 158167 times.
|
14234832 | if (new_field->stored_in_db) new_field_index_without_vgc++; |
| 12062 | 14234832 | new_field_index++; | |
| 12063 | } | ||
| 12064 | |||
| 12065 |
2/2✓ Branch 0 taken 651125 times.
✓ Branch 1 taken 2558 times.
|
653683 | if (new_field) { |
| 12066 | /* Field is not dropped. Evaluate changes bitmap for it. */ | ||
| 12067 | |||
| 12068 | /* | ||
| 12069 | Check if type of column has changed to some incompatible type. | ||
| 12070 | */ | ||
| 12071 |
4/6✓ Branch 0 taken 651125 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4801 times.
✓ Branch 3 taken 645866 times.
✓ Branch 4 taken 458 times.
✗ Branch 5 not taken.
|
651125 | switch (field->is_equal(new_field)) { |
| 12072 | 4801 | case IS_EQUAL_NO: | |
| 12073 |
3/10✓ Branch 0 taken 4801 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4801 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4801 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
4801 | DBUG_PRINT("inplace", ("Field %s: IS_EQUAL_NO for '%s'", |
| 12074 | field->field_name, thd->query().str)); | ||
| 12075 | /* New column type is incompatible with old one. */ | ||
| 12076 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 4789 times.
|
4801 | if (field->is_virtual_gcol()) |
| 12077 | 12 | ha_alter_info->handler_flags |= | |
| 12078 | Alter_inplace_info::ALTER_VIRTUAL_COLUMN_TYPE; | ||
| 12079 | else | ||
| 12080 | 4789 | ha_alter_info->handler_flags |= | |
| 12081 | Alter_inplace_info::ALTER_STORED_COLUMN_TYPE; | ||
| 12082 | 4801 | break; | |
| 12083 | 645866 | case IS_EQUAL_YES: | |
| 12084 | /* | ||
| 12085 | New column is the same as the old one or the fully compatible with | ||
| 12086 | it (for example, ENUM('a','b') was changed to ENUM('a','b','c')). | ||
| 12087 | Such a change if any can ALWAYS be carried out by simply updating | ||
| 12088 | data-dictionary without even informing storage engine. | ||
| 12089 | No flag is set in this case. | ||
| 12090 | */ | ||
| 12091 | 645866 | break; | |
| 12092 | 458 | case IS_EQUAL_PACK_LENGTH: | |
| 12093 | /* | ||
| 12094 | New column type differs from the old one, but has compatible packed | ||
| 12095 | data representation. Depending on storage engine, such a change can | ||
| 12096 | be carried out by simply updating data dictionary without changing | ||
| 12097 | actual data (for example, VARCHAR(300) is changed to VARCHAR(400)). | ||
| 12098 | |||
| 12099 | If the collation has changed, and there is an index on the column, | ||
| 12100 | we must mark this as a change in stored column type, which is | ||
| 12101 | usually rejected as inplace operation by the SE. | ||
| 12102 | */ | ||
| 12103 |
3/4✓ Branch 0 taken 458 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 328 times.
✓ Branch 3 taken 130 times.
|
458 | if (is_collation_change_for_indexed_field(*field, *new_field, |
| 12104 | ha_alter_info)) { | ||
| 12105 | 328 | ha_alter_info->handler_flags |= | |
| 12106 | Alter_inplace_info::ALTER_STORED_COLUMN_TYPE; | ||
| 12107 | } else { | ||
| 12108 | 130 | ha_alter_info->handler_flags |= | |
| 12109 | Alter_inplace_info::ALTER_COLUMN_EQUAL_PACK_LENGTH; | ||
| 12110 | } | ||
| 12111 | 458 | break; | |
| 12112 | ✗ | default: | |
| 12113 | ✗ | assert(0); | |
| 12114 | } | ||
| 12115 | |||
| 12116 | // Conversion to and from generated column is supported if stored: | ||
| 12117 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 651124 times.
|
651125 | if (field->is_gcol() != new_field->is_gcol()) { |
| 12118 |
3/8✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
|
1 | assert((field->is_gcol() && !field->is_virtual_gcol()) || |
| 12119 | (new_field->is_gcol() && !new_field->is_virtual_gcol())); | ||
| 12120 | 1 | ha_alter_info->handler_flags |= | |
| 12121 | Alter_inplace_info::ALTER_STORED_COLUMN_TYPE; | ||
| 12122 | } | ||
| 12123 | |||
| 12124 | // Modification of generation expression is supported: | ||
| 12125 |
5/6✓ Branch 0 taken 6273 times.
✓ Branch 1 taken 644852 times.
✓ Branch 2 taken 6273 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6273 times.
✓ Branch 5 taken 644852 times.
|
651125 | if (field->is_gcol() && new_field->is_gcol()) { |
| 12126 | // Modification of storage attribute is not supported | ||
| 12127 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6273 times.
|
6273 | assert(field->is_virtual_gcol() == new_field->is_virtual_gcol()); |
| 12128 |
3/4✓ Branch 0 taken 6273 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
✓ Branch 3 taken 6246 times.
|
6273 | if (!field->gcol_expr_is_equal(new_field)) { |
| 12129 |
2/2✓ Branch 0 taken 25 times.
✓ Branch 1 taken 2 times.
|
27 | if (field->is_virtual_gcol()) |
| 12130 | 25 | ha_alter_info->handler_flags |= | |
| 12131 | Alter_inplace_info::ALTER_VIRTUAL_GCOL_EXPR; | ||
| 12132 | else | ||
| 12133 | 2 | ha_alter_info->handler_flags |= | |
| 12134 | Alter_inplace_info::ALTER_STORED_GCOL_EXPR; | ||
| 12135 | } else { | ||
| 12136 |
1/2✓ Branch 0 taken 6246 times.
✗ Branch 1 not taken.
|
6246 | gcols_with_unchanged_expr.push_back(field); |
| 12137 | } | ||
| 12138 | } | ||
| 12139 | |||
| 12140 | bool field_renamed; | ||
| 12141 | /* | ||
| 12142 | InnoDB data dictionary is case sensitive so we should use | ||
| 12143 | string case sensitive comparison between fields. | ||
| 12144 | Note: strcmp branch is to be removed in future when we fix it | ||
| 12145 | in InnoDB. | ||
| 12146 | */ | ||
| 12147 |
2/2✓ Branch 0 taken 114089 times.
✓ Branch 1 taken 537036 times.
|
651125 | if (ha_alter_info->create_info->db_type->db_type == DB_TYPE_INNODB || |
| 12148 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 114089 times.
|
114089 | ha_alter_info->create_info->db_type->db_type == DB_TYPE_NDBCLUSTER) |
| 12149 | 537036 | field_renamed = strcmp(field->field_name, new_field->field_name); | |
| 12150 | else | ||
| 12151 |
1/2✓ Branch 0 taken 114089 times.
✗ Branch 1 not taken.
|
114089 | field_renamed = my_strcasecmp(system_charset_info, field->field_name, |
| 12152 | new_field->field_name); | ||
| 12153 | |||
| 12154 | /* Check if field was renamed */ | ||
| 12155 |
2/2✓ Branch 0 taken 388 times.
✓ Branch 1 taken 650737 times.
|
651125 | if (field_renamed) { |
| 12156 | 388 | field->set_flag(FIELD_IS_RENAMED); | |
| 12157 |
1/2✓ Branch 0 taken 388 times.
✗ Branch 1 not taken.
|
388 | dropped_or_renamed_cols.push_back(field); |
| 12158 | 388 | ha_alter_info->handler_flags |= Alter_inplace_info::ALTER_COLUMN_NAME; | |
| 12159 | } | ||
| 12160 | |||
| 12161 | /* Check that NULL behavior is same for old and new fields */ | ||
| 12162 |
2/2✓ Branch 0 taken 1320 times.
✓ Branch 1 taken 649805 times.
|
1302250 | if (Overlaps(new_field->flags, NOT_NULL_FLAG) != |
| 12163 | 651125 | field->is_flag_set(NOT_NULL_FLAG)) { | |
| 12164 |
2/2✓ Branch 0 taken 416 times.
✓ Branch 1 taken 904 times.
|
1320 | if (new_field->flags & NOT_NULL_FLAG) |
| 12165 | 416 | ha_alter_info->handler_flags |= | |
| 12166 | Alter_inplace_info::ALTER_COLUMN_NOT_NULLABLE; | ||
| 12167 | else | ||
| 12168 | 904 | ha_alter_info->handler_flags |= | |
| 12169 | Alter_inplace_info::ALTER_COLUMN_NULLABLE; | ||
| 12170 | } | ||
| 12171 | |||
| 12172 | /* | ||
| 12173 | We do not detect changes to default values in this loop. | ||
| 12174 | See comment above for more details. | ||
| 12175 | */ | ||
| 12176 | |||
| 12177 | /* | ||
| 12178 | Detect changes in column order. | ||
| 12179 | |||
| 12180 | Note that a stored column can't become virtual and vice versa | ||
| 12181 | thanks to check in mysql_prepare_alter_table(). | ||
| 12182 | */ | ||
| 12183 |
2/2✓ Branch 0 taken 645572 times.
✓ Branch 1 taken 5553 times.
|
651125 | if (field->stored_in_db) { |
| 12184 |
2/2✓ Branch 0 taken 5832 times.
✓ Branch 1 taken 639740 times.
|
645572 | if (old_field_index_without_vgc != new_field_index_without_vgc) |
| 12185 | 5832 | ha_alter_info->handler_flags |= | |
| 12186 | Alter_inplace_info::ALTER_STORED_COLUMN_ORDER; | ||
| 12187 | } else { | ||
| 12188 |
2/2✓ Branch 0 taken 243 times.
✓ Branch 1 taken 5310 times.
|
5553 | if (field->field_index() != new_field_index) |
| 12189 | 243 | ha_alter_info->handler_flags |= | |
| 12190 | Alter_inplace_info::ALTER_VIRTUAL_COLUMN_ORDER; | ||
| 12191 | } | ||
| 12192 | |||
| 12193 | /* Detect changes in storage type of column */ | ||
| 12194 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 651110 times.
|
651125 | if (new_field->field_storage_type() != field->field_storage_type()) |
| 12195 | 15 | ha_alter_info->handler_flags |= | |
| 12196 | Alter_inplace_info::ALTER_COLUMN_STORAGE_TYPE; | ||
| 12197 | |||
| 12198 | /* Detect changes in column format of column */ | ||
| 12199 |
2/2✓ Branch 0 taken 34 times.
✓ Branch 1 taken 651091 times.
|
651125 | if (new_field->column_format() != field->column_format()) |
| 12200 | 34 | ha_alter_info->handler_flags |= | |
| 12201 | Alter_inplace_info::ALTER_COLUMN_COLUMN_FORMAT; | ||
| 12202 | |||
| 12203 | /* | ||
| 12204 | Columns which were mentioned in CHANGE/MODIFY COLUMN clause might | ||
| 12205 | have changed their default, add their name to corresponding array. | ||
| 12206 | */ | ||
| 12207 |
2/2✓ Branch 0 taken 29838 times.
✓ Branch 1 taken 621287 times.
|
651125 | if (new_field->change) |
| 12208 |
1/2✓ Branch 0 taken 29838 times.
✗ Branch 1 not taken.
|
29838 | cols_with_default_change.push_back(new_field->change); |
| 12209 | } else { | ||
| 12210 | /* | ||
| 12211 | Field is not present in new version of table and therefore was dropped. | ||
| 12212 | */ | ||
| 12213 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2558 times.
|
2558 | assert(alter_info->flags & Alter_info::ALTER_DROP_COLUMN); |
| 12214 |
2/2✓ Branch 0 taken 261 times.
✓ Branch 1 taken 2297 times.
|
2558 | if (field->is_virtual_gcol()) { |
| 12215 | 261 | ha_alter_info->handler_flags |= Alter_inplace_info::DROP_VIRTUAL_COLUMN; | |
| 12216 | 261 | ha_alter_info->virtual_column_drop_count++; | |
| 12217 | } else | ||
| 12218 | 2297 | ha_alter_info->handler_flags |= Alter_inplace_info::DROP_STORED_COLUMN; | |
| 12219 | 2558 | field->set_flag(FIELD_IS_DROPPED); | |
| 12220 |
1/2✓ Branch 0 taken 2558 times.
✗ Branch 1 not taken.
|
2558 | dropped_or_renamed_cols.push_back(field); |
| 12221 | } | ||
| 12222 |
2/2✓ Branch 0 taken 647869 times.
✓ Branch 1 taken 5814 times.
|
653683 | if (field->stored_in_db) old_field_index_without_vgc++; |
| 12223 | } | ||
| 12224 | |||
| 12225 |
2/2✓ Branch 0 taken 10715 times.
✓ Branch 1 taken 64200 times.
|
74915 | if (alter_info->flags & Alter_info::ALTER_ADD_COLUMN) { |
| 12226 | 10715 | new_field_it.init(alter_info->create_list); | |
| 12227 |
2/2✓ Branch 0 taken 104841 times.
✓ Branch 1 taken 10715 times.
|
115556 | while ((new_field = new_field_it++)) { |
| 12228 |
2/2✓ Branch 0 taken 17484 times.
✓ Branch 1 taken 87357 times.
|
104841 | if (!new_field->field) { |
| 12229 | /* | ||
| 12230 | Field is not present in old version of table and therefore was added. | ||
| 12231 | */ | ||
| 12232 |
2/2✓ Branch 0 taken 903 times.
✓ Branch 1 taken 16581 times.
|
17484 | if (new_field->is_virtual_gcol()) { |
| 12233 | 903 | ha_alter_info->handler_flags |= | |
| 12234 | Alter_inplace_info::ADD_VIRTUAL_COLUMN; | ||
| 12235 | 903 | ha_alter_info->virtual_column_add_count++; | |
| 12236 |
4/4✓ Branch 0 taken 16484 times.
✓ Branch 1 taken 97 times.
✓ Branch 2 taken 101 times.
✓ Branch 3 taken 16383 times.
|
16581 | } else if (new_field->gcol_info || new_field->m_default_val_expr) |
| 12237 | 198 | ha_alter_info->handler_flags |= | |
| 12238 | Alter_inplace_info::ADD_STORED_GENERATED_COLUMN; | ||
| 12239 | else | ||
| 12240 | 16383 | ha_alter_info->handler_flags |= | |
| 12241 | Alter_inplace_info::ADD_STORED_BASE_COLUMN; | ||
| 12242 | } | ||
| 12243 | } | ||
| 12244 | /* One of these should be set since Alter_info::ALTER_ADD_COLUMN was set. */ | ||
| 12245 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10715 times.
|
10715 | assert(ha_alter_info->handler_flags & |
| 12246 | (Alter_inplace_info::ADD_VIRTUAL_COLUMN | | ||
| 12247 | Alter_inplace_info::ADD_STORED_BASE_COLUMN | | ||
| 12248 | Alter_inplace_info::ADD_STORED_GENERATED_COLUMN)); | ||
| 12249 | } | ||
| 12250 | |||
| 12251 | /* | ||
| 12252 | Add columns mentioned in SET/DROP DEFAULT clause to array of column names | ||
| 12253 | which might have changed default. | ||
| 12254 | */ | ||
| 12255 |
3/4✓ Branch 0 taken 74915 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 244 times.
✓ Branch 3 taken 74915 times.
|
75159 | for (const Alter_column *alter : alter_info->alter_list) { |
| 12256 |
6/6✓ Branch 0 taken 145 times.
✓ Branch 1 taken 99 times.
✓ Branch 2 taken 80 times.
✓ Branch 3 taken 65 times.
✓ Branch 4 taken 179 times.
✓ Branch 5 taken 65 times.
|
389 | if (alter->change_type() == Alter_column::Type::SET_DEFAULT || |
| 12257 | 145 | alter->change_type() == Alter_column::Type::DROP_DEFAULT) { | |
| 12258 |
1/2✓ Branch 0 taken 179 times.
✗ Branch 1 not taken.
|
179 | cols_with_default_change.push_back(alter->name); |
| 12259 | } | ||
| 12260 | } | ||
| 12261 | |||
| 12262 | /* | ||
| 12263 | Detect cases when we have generated columns that depend on columns | ||
| 12264 | which were swapped (by renaming them) or replaced (by dropping and | ||
| 12265 | then adding column with the same name). Also detect cases when | ||
| 12266 | generated columns depend on the DEFAULT function on a column and | ||
| 12267 | column default might have changed. | ||
| 12268 | |||
| 12269 | Storage engine might be unable to do such operation inplace as indexes | ||
| 12270 | or value of stored generated columns might become invalid and require | ||
| 12271 | re-evaluation by SQL-layer. | ||
| 12272 | */ | ||
| 12273 |
4/6✓ Branch 0 taken 74915 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 74915 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6246 times.
✓ Branch 5 taken 74915 times.
|
81161 | for (Field *vfield : gcols_with_unchanged_expr) { |
| 12274 | 6246 | bool gcol_needs_reeval = false; | |
| 12275 |
4/6✓ Branch 0 taken 6246 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6246 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 601 times.
✓ Branch 5 taken 6246 times.
|
6847 | for (const char *col_name : cols_with_default_change) { |
| 12276 |
2/4✓ Branch 0 taken 601 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 601 times.
|
601 | if (vfield->gcol_info->expr_item->walk( |
| 12277 | &Item::check_gcol_depend_default_processor, enum_walk::POSTFIX, | ||
| 12278 | reinterpret_cast<uchar *>(const_cast<char *>(col_name)))) { | ||
| 12279 | ✗ | gcol_needs_reeval = true; | |
| 12280 | ✗ | break; | |
| 12281 | } | ||
| 12282 | } | ||
| 12283 | |||
| 12284 |
6/8✓ Branch 0 taken 6246 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6246 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 697 times.
✓ Branch 5 taken 5549 times.
✓ Branch 6 taken 697 times.
✓ Branch 7 taken 5549 times.
|
6246 | if (!gcol_needs_reeval && !dropped_or_renamed_cols.empty()) { |
| 12285 | 697 | MY_BITMAP dependent_fields; | |
| 12286 | my_bitmap_map | ||
| 12287 | bitbuf[bitmap_buffer_size(MAX_FIELDS) / sizeof(my_bitmap_map)]; | ||
| 12288 |
1/2✓ Branch 0 taken 697 times.
✗ Branch 1 not taken.
|
697 | bitmap_init(&dependent_fields, bitbuf, table->s->fields); |
| 12289 | 697 | MY_BITMAP *save_old_read_set = table->read_set; | |
| 12290 | 697 | table->read_set = &dependent_fields; | |
| 12291 | 697 | Mark_field mark_fld(MARK_COLUMNS_TEMP); | |
| 12292 |
1/2✓ Branch 0 taken 697 times.
✗ Branch 1 not taken.
|
697 | vfield->gcol_info->expr_item->walk(&Item::mark_field_in_map, |
| 12293 | enum_walk::PREFIX, | ||
| 12294 | reinterpret_cast<uchar *>(&mark_fld)); | ||
| 12295 |
4/6✓ Branch 0 taken 697 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 697 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 709 times.
✓ Branch 5 taken 697 times.
|
1406 | for (const Field *dr_field : dropped_or_renamed_cols) { |
| 12296 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 709 times.
|
709 | if (bitmap_is_set(table->read_set, dr_field->field_index())) { |
| 12297 | ✗ | gcol_needs_reeval = true; | |
| 12298 | ✗ | break; | |
| 12299 | } | ||
| 12300 | } | ||
| 12301 | 697 | table->read_set = save_old_read_set; | |
| 12302 | } | ||
| 12303 | |||
| 12304 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6246 times.
|
6246 | if (gcol_needs_reeval) { |
| 12305 | ✗ | if (vfield->is_virtual_gcol()) | |
| 12306 | ✗ | ha_alter_info->handler_flags |= Alter_inplace_info::VIRTUAL_GCOL_REEVAL; | |
| 12307 | else | ||
| 12308 | ✗ | ha_alter_info->handler_flags |= Alter_inplace_info::STORED_GCOL_REEVAL; | |
| 12309 | } | ||
| 12310 | |||
| 12311 | /* | ||
| 12312 | Stop our search early if flags indicating re-evaluation of both | ||
| 12313 | virtual and stored generated columns are already set. | ||
| 12314 | */ | ||
| 12315 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6246 times.
|
6246 | if ((ha_alter_info->handler_flags & |
| 12316 | (Alter_inplace_info::VIRTUAL_GCOL_REEVAL | | ||
| 12317 | Alter_inplace_info::STORED_GCOL_REEVAL)) == | ||
| 12318 | (Alter_inplace_info::VIRTUAL_GCOL_REEVAL | | ||
| 12319 | Alter_inplace_info::STORED_GCOL_REEVAL)) | ||
| 12320 | ✗ | break; | |
| 12321 | } | ||
| 12322 | |||
| 12323 | /* | ||
| 12324 | Go through keys and check if the original ones are compatible | ||
| 12325 | with new table. | ||
| 12326 | */ | ||
| 12327 | KEY *table_key; | ||
| 12328 | 74915 | KEY *table_key_end = table->key_info + table->s->keys; | |
| 12329 | KEY *new_key; | ||
| 12330 | 74915 | KEY *new_key_end = ha_alter_info->key_info_buffer + ha_alter_info->key_count; | |
| 12331 | |||
| 12332 |
5/8✓ Branch 0 taken 74915 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 74915 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 74913 times.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
|
74915 | DBUG_PRINT("info", ("index count old: %d new: %d", table->s->keys, |
| 12333 | ha_alter_info->key_count)); | ||
| 12334 | |||
| 12335 | /* | ||
| 12336 | First, we need to handle keys being renamed, otherwise code handling | ||
| 12337 | dropping/addition of keys might be confused in some situations. | ||
| 12338 | */ | ||
| 12339 |
2/2✓ Branch 0 taken 78529 times.
✓ Branch 1 taken 74915 times.
|
153444 | for (table_key = table->key_info; table_key < table_key_end; table_key++) |
| 12340 | 78529 | table_key->flags &= ~HA_KEY_RENAMED; | |
| 12341 |
2/2✓ Branch 0 taken 85315 times.
✓ Branch 1 taken 74915 times.
|
160230 | for (new_key = ha_alter_info->key_info_buffer; new_key < new_key_end; |
| 12342 | new_key++) | ||
| 12343 | 85315 | new_key->flags &= ~HA_KEY_RENAMED; | |
| 12344 | |||
| 12345 |
3/4✓ Branch 0 taken 74915 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 115 times.
✓ Branch 3 taken 74915 times.
|
75030 | for (const Alter_rename_key *rename_key : alter_info->alter_rename_key_list) { |
| 12346 | table_key = | ||
| 12347 |
1/2✓ Branch 0 taken 115 times.
✗ Branch 1 not taken.
|
115 | find_key_ci(rename_key->old_name, table->key_info, table_key_end); |
| 12348 |
1/2✓ Branch 0 taken 115 times.
✗ Branch 1 not taken.
|
115 | new_key = find_key_ci(rename_key->new_name, ha_alter_info->key_info_buffer, |
| 12349 | new_key_end); | ||
| 12350 | |||
| 12351 | 115 | table_key->flags |= HA_KEY_RENAMED; | |
| 12352 | 115 | new_key->flags |= HA_KEY_RENAMED; | |
| 12353 | |||
| 12354 |
3/4✓ Branch 0 taken 115 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 113 times.
✓ Branch 3 taken 2 times.
|
115 | if (!has_index_def_changed(ha_alter_info, table_key, new_key)) { |
| 12355 | /* Key was not modified in any significant way but still was renamed. */ | ||
| 12356 | 113 | ha_alter_info->handler_flags |= Alter_inplace_info::RENAME_INDEX; | |
| 12357 |
1/2✓ Branch 0 taken 113 times.
✗ Branch 1 not taken.
|
113 | ha_alter_info->add_renamed_key(table_key, new_key); |
| 12358 | |||
| 12359 | /* | ||
| 12360 | Check for insignificant changes which do not call for index | ||
| 12361 | recreation, but still require update of .FRM. | ||
| 12362 | */ | ||
| 12363 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 113 times.
|
113 | if (table_key->is_algorithm_explicit != new_key->is_algorithm_explicit) |
| 12364 | ✗ | ha_alter_info->handler_flags |= Alter_inplace_info::CHANGE_INDEX_OPTION; | |
| 12365 | } else { | ||
| 12366 | /* Key was modified. */ | ||
| 12367 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | ha_alter_info->add_modified_key(table_key, new_key); |
| 12368 | } | ||
| 12369 | } | ||
| 12370 | |||
| 12371 | 75014 | for (const Alter_index_visibility *alter_index_visibility : | |
| 12372 |
2/2✓ Branch 0 taken 100 times.
✓ Branch 1 taken 74914 times.
|
149929 | alter_info->alter_index_visibility_list) { |
| 12373 | 100 | const char *name = alter_index_visibility->name(); | |
| 12374 |
1/2✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
|
100 | table_key = find_key_ci(name, table->key_info, table_key_end); |
| 12375 |
1/2✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
|
100 | new_key = find_key_ci(name, ha_alter_info->key_info_buffer, new_key_end); |
| 12376 | |||
| 12377 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 99 times.
|
100 | if (new_key == nullptr) { |
| 12378 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_KEY_DOES_NOT_EXITS, MYF(0), name, table->s->table_name.str); |
| 12379 | 1 | return true; | |
| 12380 | } | ||
| 12381 | |||
| 12382 | 99 | new_key->is_visible = alter_index_visibility->is_visible(); | |
| 12383 | 99 | ha_alter_info->handler_flags |= Alter_inplace_info::RENAME_INDEX; | |
| 12384 |
1/2✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
|
99 | ha_alter_info->add_altered_index_visibility(table_key, new_key); |
| 12385 | } | ||
| 12386 | |||
| 12387 | /* | ||
| 12388 | Step through all keys of the old table and search matching new keys. | ||
| 12389 | */ | ||
| 12390 |
2/2✓ Branch 0 taken 78527 times.
✓ Branch 1 taken 74914 times.
|
153441 | for (table_key = table->key_info; table_key < table_key_end; table_key++) { |
| 12391 | /* Skip renamed keys. */ | ||
| 12392 |
2/2✓ Branch 0 taken 114 times.
✓ Branch 1 taken 78413 times.
|
78527 | if (table_key->flags & HA_KEY_RENAMED) continue; |
| 12393 | |||
| 12394 | 78413 | new_key = find_key_cs(table_key->name, ha_alter_info->key_info_buffer, | |
| 12395 | new_key_end); | ||
| 12396 | |||
| 12397 |
2/2✓ Branch 0 taken 5809 times.
✓ Branch 1 taken 72604 times.
|
78413 | if (new_key == nullptr) { |
| 12398 | /* Matching new key not found. This means the key should be dropped. */ | ||
| 12399 |
1/2✓ Branch 0 taken 5809 times.
✗ Branch 1 not taken.
|
5809 | ha_alter_info->add_dropped_key(table_key); |
| 12400 |
3/4✓ Branch 0 taken 72604 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2698 times.
✓ Branch 3 taken 69906 times.
|
72604 | } else if (has_index_def_changed(ha_alter_info, table_key, new_key)) { |
| 12401 | /* Key was modified. */ | ||
| 12402 |
1/2✓ Branch 0 taken 2698 times.
✗ Branch 1 not taken.
|
2698 | ha_alter_info->add_modified_key(table_key, new_key); |
| 12403 | } else { | ||
| 12404 | /* | ||
| 12405 | Key was not modified in significant way. Still we need to check | ||
| 12406 | for insignificant changes which do not call for index recreation, | ||
| 12407 | but still require update of .FRM. | ||
| 12408 | */ | ||
| 12409 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 69904 times.
|
69906 | if (table_key->is_algorithm_explicit != new_key->is_algorithm_explicit) |
| 12410 | 2 | ha_alter_info->handler_flags |= Alter_inplace_info::CHANGE_INDEX_OPTION; | |
| 12411 | } | ||
| 12412 | } | ||
| 12413 | |||
| 12414 | /* | ||
| 12415 | Step through all keys of the new table and find matching old keys. | ||
| 12416 | */ | ||
| 12417 |
2/2✓ Branch 0 taken 85313 times.
✓ Branch 1 taken 74914 times.
|
160227 | for (new_key = ha_alter_info->key_info_buffer; new_key < new_key_end; |
| 12418 | new_key++) { | ||
| 12419 | /* Skip renamed keys. */ | ||
| 12420 |
2/2✓ Branch 0 taken 114 times.
✓ Branch 1 taken 85199 times.
|
85313 | if (new_key->flags & HA_KEY_RENAMED) continue; |
| 12421 | |||
| 12422 |
2/2✓ Branch 0 taken 12595 times.
✓ Branch 1 taken 72604 times.
|
85199 | if (!find_key_cs(new_key->name, table->key_info, table_key_end)) { |
| 12423 | /* Matching old key not found. This means the key should be added. */ | ||
| 12424 |
1/2✓ Branch 0 taken 12595 times.
✗ Branch 1 not taken.
|
12595 | ha_alter_info->add_added_key(new_key); |
| 12425 | } | ||
| 12426 | } | ||
| 12427 | |||
| 12428 | /* | ||
| 12429 | Sort index_add_buffer according to how key_info_buffer is sorted. | ||
| 12430 | I.e. with primary keys first - see sort_keys(). | ||
| 12431 | */ | ||
| 12432 | 74914 | std::sort(ha_alter_info->index_add_buffer, | |
| 12433 |
1/2✓ Branch 0 taken 74914 times.
✗ Branch 1 not taken.
|
74914 | ha_alter_info->index_add_buffer + ha_alter_info->index_add_count); |
| 12434 | |||
| 12435 | /* Now let us calculate flags for storage engine API. */ | ||
| 12436 | |||
| 12437 | /* Count all existing candidate keys. */ | ||
| 12438 |
2/2✓ Branch 0 taken 78527 times.
✓ Branch 1 taken 74914 times.
|
153441 | for (table_key = table->key_info; table_key < table_key_end; table_key++) { |
| 12439 | /* | ||
| 12440 | Check if key is a candidate key, This key is either already primary key | ||
| 12441 | or could be promoted to primary key if the original primary key is | ||
| 12442 | dropped. | ||
| 12443 | In MySQL one is allowed to create primary key with partial fields (i.e. | ||
| 12444 | primary key which is not considered candidate). For simplicity we count | ||
| 12445 | such key as a candidate key here. | ||
| 12446 | */ | ||
| 12447 |
6/6✓ Branch 0 taken 32544 times.
✓ Branch 1 taken 45983 times.
✓ Branch 2 taken 2886 times.
✓ Branch 3 taken 29658 times.
✓ Branch 4 taken 48869 times.
✓ Branch 5 taken 29658 times.
|
111071 | if (((uint)(table_key - table->key_info) == table->s->primary_key) || |
| 12448 | 32544 | is_candidate_key(table_key)) | |
| 12449 | 48869 | candidate_key_count++; | |
| 12450 | } | ||
| 12451 | |||
| 12452 | /* Figure out what kind of indexes we are dropping. */ | ||
| 12453 | KEY **dropped_key; | ||
| 12454 | 74914 | KEY **dropped_key_end = | |
| 12455 | 74914 | ha_alter_info->index_drop_buffer + ha_alter_info->index_drop_count; | |
| 12456 | |||
| 12457 | 83423 | for (dropped_key = ha_alter_info->index_drop_buffer; | |
| 12458 |
2/2✓ Branch 0 taken 8509 times.
✓ Branch 1 taken 74914 times.
|
83423 | dropped_key < dropped_key_end; dropped_key++) { |
| 12459 | 8509 | table_key = *dropped_key; | |
| 12460 | |||
| 12461 |
2/2✓ Branch 0 taken 4316 times.
✓ Branch 1 taken 4193 times.
|
8509 | if (table_key->flags & HA_NOSAME) { |
| 12462 | /* | ||
| 12463 | Unique key. Check for PRIMARY KEY. Also see comment about primary | ||
| 12464 | and candidate keys above. | ||
| 12465 | */ | ||
| 12466 |
2/2✓ Branch 0 taken 2443 times.
✓ Branch 1 taken 1873 times.
|
4316 | if ((uint)(table_key - table->key_info) == table->s->primary_key) { |
| 12467 | 2443 | ha_alter_info->handler_flags |= Alter_inplace_info::DROP_PK_INDEX; | |
| 12468 | 2443 | candidate_key_count--; | |
| 12469 | } else { | ||
| 12470 | 1873 | ha_alter_info->handler_flags |= Alter_inplace_info::DROP_UNIQUE_INDEX; | |
| 12471 |
2/2✓ Branch 0 taken 34 times.
✓ Branch 1 taken 1839 times.
|
1873 | if (is_candidate_key(table_key)) candidate_key_count--; |
| 12472 | } | ||
| 12473 | } else | ||
| 12474 | 4193 | ha_alter_info->handler_flags |= Alter_inplace_info::DROP_INDEX; | |
| 12475 | } | ||
| 12476 | |||
| 12477 | /* Now figure out what kind of indexes we are adding. */ | ||
| 12478 |
2/2✓ Branch 0 taken 15295 times.
✓ Branch 1 taken 74914 times.
|
90209 | for (uint add_key_idx = 0; add_key_idx < ha_alter_info->index_add_count; |
| 12479 | add_key_idx++) { | ||
| 12480 | 15295 | new_key = ha_alter_info->key_info_buffer + | |
| 12481 | 15295 | ha_alter_info->index_add_buffer[add_key_idx]; | |
| 12482 | |||
| 12483 |
2/2✓ Branch 0 taken 6387 times.
✓ Branch 1 taken 8908 times.
|
15295 | if (new_key->flags & HA_NOSAME) { |
| 12484 | bool is_pk = | ||
| 12485 |
1/2✓ Branch 0 taken 6387 times.
✗ Branch 1 not taken.
|
6387 | !my_strcasecmp(system_charset_info, new_key->name, primary_key_name); |
| 12486 | |||
| 12487 |
2/2✓ Branch 0 taken 6116 times.
✓ Branch 1 taken 271 times.
|
6387 | if ((!(new_key->flags & HA_KEY_HAS_PART_KEY_SEG) && |
| 12488 |
4/4✓ Branch 0 taken 2707 times.
✓ Branch 1 taken 3409 times.
✓ Branch 2 taken 71 times.
✓ Branch 3 taken 2907 times.
|
6387 | !(new_key->flags & HA_NULL_PART_KEY)) || |
| 12489 | is_pk) { | ||
| 12490 | /* Candidate key or primary key! */ | ||
| 12491 |
4/4✓ Branch 0 taken 137 times.
✓ Branch 1 taken 3343 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 131 times.
|
3480 | if (candidate_key_count == 0 || is_pk) |
| 12492 | 3349 | ha_alter_info->handler_flags |= Alter_inplace_info::ADD_PK_INDEX; | |
| 12493 | else | ||
| 12494 | 131 | ha_alter_info->handler_flags |= Alter_inplace_info::ADD_UNIQUE_INDEX; | |
| 12495 | 3480 | candidate_key_count++; | |
| 12496 | } else { | ||
| 12497 | 2907 | ha_alter_info->handler_flags |= Alter_inplace_info::ADD_UNIQUE_INDEX; | |
| 12498 | } | ||
| 12499 | } else { | ||
| 12500 |
2/2✓ Branch 0 taken 108 times.
✓ Branch 1 taken 8800 times.
|
8908 | if (new_key->flags & HA_SPATIAL) { |
| 12501 | 108 | ha_alter_info->handler_flags |= Alter_inplace_info::ADD_SPATIAL_INDEX; | |
| 12502 | } else { | ||
| 12503 | 8800 | ha_alter_info->handler_flags |= Alter_inplace_info::ADD_INDEX; | |
| 12504 | } | ||
| 12505 | } | ||
| 12506 | } | ||
| 12507 | |||
| 12508 | 74914 | return false; | |
| 12509 | 74915 | } | |
| 12510 | |||
| 12511 | /** | ||
| 12512 | Mark fields participating in newly added indexes in TABLE object which | ||
| 12513 | corresponds to new version of altered table. | ||
| 12514 | |||
| 12515 | @param ha_alter_info Alter_inplace_info describing in-place ALTER. | ||
| 12516 | @param altered_table TABLE object for new version of TABLE in which | ||
| 12517 | fields should be marked. | ||
| 12518 | */ | ||
| 12519 | |||
| 12520 | 74894 | static void update_altered_table(const Alter_inplace_info &ha_alter_info, | |
| 12521 | TABLE *altered_table) { | ||
| 12522 | uint field_idx, add_key_idx; | ||
| 12523 | KEY *key; | ||
| 12524 | KEY_PART_INFO *end, *key_part; | ||
| 12525 | |||
| 12526 | /* | ||
| 12527 | Clear marker for all fields, as we are going to set it only | ||
| 12528 | for fields which participate in new indexes. | ||
| 12529 | */ | ||
| 12530 |
2/2✓ Branch 0 taken 668548 times.
✓ Branch 1 taken 74894 times.
|
743442 | for (field_idx = 0; field_idx < altered_table->s->fields; ++field_idx) |
| 12531 | 668548 | altered_table->field[field_idx]->clear_flag(FIELD_IN_ADD_INDEX); | |
| 12532 | |||
| 12533 | /* | ||
| 12534 | Go through array of newly added indexes and mark fields | ||
| 12535 | participating in them. | ||
| 12536 | */ | ||
| 12537 |
2/2✓ Branch 0 taken 15294 times.
✓ Branch 1 taken 74894 times.
|
90188 | for (add_key_idx = 0; add_key_idx < ha_alter_info.index_add_count; |
| 12538 | add_key_idx++) { | ||
| 12539 | 15294 | key = ha_alter_info.key_info_buffer + | |
| 12540 | 15294 | ha_alter_info.index_add_buffer[add_key_idx]; | |
| 12541 | |||
| 12542 | 15294 | end = key->key_part + key->user_defined_key_parts; | |
| 12543 |
2/2✓ Branch 0 taken 23291 times.
✓ Branch 1 taken 15294 times.
|
38585 | for (key_part = key->key_part; key_part < end; key_part++) |
| 12544 | 23291 | altered_table->field[key_part->fieldnr]->set_flag(FIELD_IN_ADD_INDEX); | |
| 12545 | } | ||
| 12546 | 74894 | } | |
| 12547 | |||
| 12548 | /** | ||
| 12549 | Initialize TABLE::field for the new table with appropriate | ||
| 12550 | column static defaults. | ||
| 12551 | |||
| 12552 | @note Can be plain default values from TABLE_SHARE::default_values | ||
| 12553 | or datetime function defaults. We don't handle general | ||
| 12554 | expression defaults here as their values need to be evaluated | ||
| 12555 | for each row and such evaluation might result in error. | ||
| 12556 | |||
| 12557 | @param altered_table TABLE object for the new version of the table. | ||
| 12558 | @param create Create_field list for new version of the table, | ||
| 12559 | which is used for identifying new columns. | ||
| 12560 | */ | ||
| 12561 | |||
| 12562 | 95364 | static void set_column_static_defaults(TABLE *altered_table, | |
| 12563 | List<Create_field> &create) { | ||
| 12564 | // Initialize TABLE::field default values | ||
| 12565 | 95364 | restore_record(altered_table, s->default_values); | |
| 12566 | |||
| 12567 | // Now set datetime expression defaults for new columns. | ||
| 12568 |
1/2✓ Branch 0 taken 95364 times.
✗ Branch 1 not taken.
|
95364 | List_iterator<Create_field> iter(create); |
| 12569 |
2/2✓ Branch 0 taken 777052 times.
✓ Branch 1 taken 95364 times.
|
872416 | for (uint i = 0; i < altered_table->s->fields; ++i) { |
| 12570 | 777052 | const Create_field *definition = iter++; | |
| 12571 |
6/6✓ Branch 0 taken 21751 times.
✓ Branch 1 taken 755301 times.
✓ Branch 2 taken 243 times.
✓ Branch 3 taken 21508 times.
✓ Branch 4 taken 243 times.
✓ Branch 5 taken 776809 times.
|
798803 | if (definition->field == nullptr && |
| 12572 | 21751 | altered_table->field[i]->has_insert_default_datetime_value_expression()) | |
| 12573 |
1/2✓ Branch 0 taken 243 times.
✗ Branch 1 not taken.
|
243 | altered_table->field[i]->evaluate_insert_default_function(); |
| 12574 | } | ||
| 12575 | 95364 | } | |
| 12576 | |||
| 12577 | /** | ||
| 12578 | Compare two tables to see if their metadata are compatible. | ||
| 12579 | One table specified by a TABLE instance, the other using Alter_info | ||
| 12580 | and HA_CREATE_INFO. | ||
| 12581 | |||
| 12582 | @param thd Thread handler | ||
| 12583 | @param[in] table The first table. | ||
| 12584 | @param[in] alter_info Alter options, fields and keys for the | ||
| 12585 | second table. | ||
| 12586 | @param[in] create_info Create options for the second table. | ||
| 12587 | @param[out] metadata_equal Result of comparison. | ||
| 12588 | |||
| 12589 | @retval true error | ||
| 12590 | @retval false success | ||
| 12591 | */ | ||
| 12592 | |||
| 12593 | 254 | bool mysql_compare_tables(THD *thd, TABLE *table, Alter_info *alter_info, | |
| 12594 | HA_CREATE_INFO *create_info, bool *metadata_equal) { | ||
| 12595 |
1/2✓ Branch 0 taken 254 times.
✗ Branch 1 not taken.
|
254 | DBUG_TRACE; |
| 12596 | |||
| 12597 | 254 | uint changes = IS_EQUAL_NO; | |
| 12598 | uint key_count; | ||
| 12599 | 254 | uint fk_key_count = 0; | |
| 12600 | 254 | List_iterator_fast<Create_field> tmp_new_field_it; | |
| 12601 | 254 | *metadata_equal = false; | |
| 12602 | |||
| 12603 | /* | ||
| 12604 | Create a copy of alter_info. | ||
| 12605 | To compare definitions, we need to "prepare" the definition - transform it | ||
| 12606 | from parser output to a format that describes the table layout (all column | ||
| 12607 | defaults are initialized, duplicate columns are removed). This is done by | ||
| 12608 | mysql_prepare_create_table. Unfortunately, mysql_prepare_create_table | ||
| 12609 | performs its transformations "in-place", that is, modifies the argument. | ||
| 12610 | Since we would like to keep mysql_compare_tables() idempotent (not altering | ||
| 12611 | any of the arguments) we create a copy of alter_info here and pass it to | ||
| 12612 | mysql_prepare_create_table, then use the result to compare the tables, and | ||
| 12613 | then destroy the copy. | ||
| 12614 | */ | ||
| 12615 |
1/2✓ Branch 0 taken 254 times.
✗ Branch 1 not taken.
|
254 | Alter_info tmp_alter_info(*alter_info, thd->mem_root); |
| 12616 | 254 | KEY *key_info_buffer = nullptr; | |
| 12617 | 254 | FOREIGN_KEY *fk_key_info_buffer = nullptr; | |
| 12618 | |||
| 12619 | /* Create the prepared information. */ | ||
| 12620 |
2/4✓ Branch 0 taken 254 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 254 times.
|
254 | if (mysql_prepare_create_table(thd, |
| 12621 | "", // Not used | ||
| 12622 | "", // Not used | ||
| 12623 | create_info, &tmp_alter_info, table->file, | ||
| 12624 | false, // Not used | ||
| 12625 | &key_info_buffer, &key_count, | ||
| 12626 | &fk_key_info_buffer, &fk_key_count, nullptr, 0, | ||
| 12627 | nullptr, 0, 0, false)) | ||
| 12628 | ✗ | return true; | |
| 12629 | |||
| 12630 | /* Some very basic checks. */ | ||
| 12631 | 761 | if (table->s->fields != alter_info->create_list.elements || | |
| 12632 |
7/10✓ Branch 0 taken 253 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 253 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 253 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 253 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 253 times.
|
507 | table->s->db_type() != create_info->db_type || table->s->tmp_table || |
| 12633 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 253 times.
|
253 | (table->s->row_type != create_info->row_type)) |
| 12634 | 1 | return false; | |
| 12635 | |||
| 12636 | /* Go through fields and check if they are compatible. */ | ||
| 12637 | 253 | tmp_new_field_it.init(tmp_alter_info.create_list); | |
| 12638 |
2/2✓ Branch 0 taken 618 times.
✓ Branch 1 taken 249 times.
|
867 | for (Field **f_ptr = table->field; *f_ptr; f_ptr++) { |
| 12639 | 618 | Field *field = *f_ptr; | |
| 12640 | 618 | const Create_field *tmp_new_field = tmp_new_field_it++; | |
| 12641 | |||
| 12642 | /* Check to see if both fields are alike. */ | ||
| 12643 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 617 times.
|
618 | if (tmp_new_field->is_virtual_gcol() != field->is_virtual_gcol()) { |
| 12644 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_UNSUPPORTED_ACTION_ON_GENERATED_COLUMN, MYF(0), |
| 12645 | "Exchanging partitions for non-generated columns"); | ||
| 12646 | 1 | return false; | |
| 12647 | } | ||
| 12648 | |||
| 12649 | /* Check that NULL behavior is the same. */ | ||
| 12650 | 1234 | if ((tmp_new_field->flags & NOT_NULL_FLAG) != | |
| 12651 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 616 times.
|
617 | field->is_flag_set(NOT_NULL_FLAG)) |
| 12652 | 1 | return false; | |
| 12653 | |||
| 12654 | /* Check if field was renamed */ | ||
| 12655 |
3/4✓ Branch 0 taken 616 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 615 times.
|
616 | if (my_strcasecmp(system_charset_info, field->field_name, |
| 12656 | tmp_new_field->field_name)) | ||
| 12657 | 1 | return false; | |
| 12658 | |||
| 12659 | /* Evaluate changes bitmap and send to check_if_incompatible_data() */ | ||
| 12660 |
1/2✓ Branch 0 taken 615 times.
✗ Branch 1 not taken.
|
615 | uint field_changes = field->is_equal(tmp_new_field); |
| 12661 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 614 times.
|
615 | if (field_changes != IS_EQUAL_YES) return false; |
| 12662 | |||
| 12663 | 614 | changes |= field_changes; | |
| 12664 | } | ||
| 12665 | |||
| 12666 | /* Check if changes are compatible with current handler. */ | ||
| 12667 |
2/4✓ Branch 0 taken 249 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 249 times.
|
249 | if (table->file->check_if_incompatible_data(create_info, changes)) |
| 12668 | ✗ | return false; | |
| 12669 | |||
| 12670 | /* Go through keys and check if they are compatible. */ | ||
| 12671 | KEY *table_key; | ||
| 12672 | 249 | KEY *table_key_end = table->key_info + table->s->keys; | |
| 12673 | KEY *new_key; | ||
| 12674 | 249 | KEY *new_key_end = key_info_buffer + key_count; | |
| 12675 | |||
| 12676 | /* Step through all keys of the first table and search matching keys. */ | ||
| 12677 |
2/2✓ Branch 0 taken 245 times.
✓ Branch 1 taken 245 times.
|
490 | for (table_key = table->key_info; table_key < table_key_end; table_key++) { |
| 12678 | /* Search a key with the same name. */ | ||
| 12679 |
2/2✓ Branch 0 taken 289 times.
✓ Branch 1 taken 4 times.
|
293 | for (new_key = key_info_buffer; new_key < new_key_end; new_key++) { |
| 12680 |
2/2✓ Branch 0 taken 241 times.
✓ Branch 1 taken 48 times.
|
289 | if (!strcmp(table_key->name, new_key->name)) break; |
| 12681 | } | ||
| 12682 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 241 times.
|
245 | if (new_key >= new_key_end) return false; |
| 12683 | |||
| 12684 | /* Check that the key types are compatible. */ | ||
| 12685 |
1/2✓ Branch 0 taken 241 times.
✗ Branch 1 not taken.
|
241 | if ((table_key->algorithm != new_key->algorithm) || |
| 12686 | 241 | ((table_key->flags & HA_KEYFLAG_MASK) != | |
| 12687 |
1/2✓ Branch 0 taken 241 times.
✗ Branch 1 not taken.
|
241 | (new_key->flags & HA_KEYFLAG_MASK)) || |
| 12688 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 241 times.
|
241 | (table_key->user_defined_key_parts != new_key->user_defined_key_parts)) |
| 12689 | ✗ | return false; | |
| 12690 | |||
| 12691 | /* Check that the key parts remain compatible. */ | ||
| 12692 | KEY_PART_INFO *table_part; | ||
| 12693 | 241 | KEY_PART_INFO *table_part_end = | |
| 12694 | 241 | table_key->key_part + table_key->user_defined_key_parts; | |
| 12695 | KEY_PART_INFO *new_part; | ||
| 12696 | 241 | for (table_part = table_key->key_part, new_part = new_key->key_part; | |
| 12697 |
2/2✓ Branch 0 taken 272 times.
✓ Branch 1 taken 241 times.
|
513 | table_part < table_part_end; table_part++, new_part++) { |
| 12698 | /* | ||
| 12699 | Key definition is different if we are using a different field or | ||
| 12700 | if the used key part length is different. We know that the fields | ||
| 12701 | are equal. Comparing field numbers is sufficient. | ||
| 12702 | */ | ||
| 12703 |
1/2✓ Branch 0 taken 272 times.
✗ Branch 1 not taken.
|
272 | if ((table_part->length != new_part->length) || |
| 12704 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 272 times.
|
272 | (table_part->fieldnr - 1 != new_part->fieldnr)) |
| 12705 | ✗ | return false; | |
| 12706 | } | ||
| 12707 | } | ||
| 12708 | |||
| 12709 | /* Step through all keys of the second table and find matching keys. */ | ||
| 12710 |
2/2✓ Branch 0 taken 238 times.
✓ Branch 1 taken 244 times.
|
482 | for (new_key = key_info_buffer; new_key < new_key_end; new_key++) { |
| 12711 | /* Search a key with the same name. */ | ||
| 12712 |
2/2✓ Branch 0 taken 280 times.
✓ Branch 1 taken 1 times.
|
281 | for (table_key = table->key_info; table_key < table_key_end; table_key++) { |
| 12713 |
2/2✓ Branch 0 taken 237 times.
✓ Branch 1 taken 43 times.
|
280 | if (!strcmp(table_key->name, new_key->name)) break; |
| 12714 | } | ||
| 12715 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 237 times.
|
238 | if (table_key >= table_key_end) return false; |
| 12716 | } | ||
| 12717 | |||
| 12718 | 244 | *metadata_equal = true; // Tables are compatible | |
| 12719 | 244 | return false; | |
| 12720 | 254 | } | |
| 12721 | |||
| 12722 | /** | ||
| 12723 | Report a zero date warning if no default value is supplied | ||
| 12724 | for the DATE/DATETIME 'NOT NULL' field and 'NO_ZERO_DATE' | ||
| 12725 | sql_mode is enabled. | ||
| 12726 | |||
| 12727 | @param thd Thread handle. | ||
| 12728 | @param datetime_field DATE/DATETIME column definition. | ||
| 12729 | */ | ||
| 12730 | 11 | static bool push_zero_date_warning(THD *thd, Create_field *datetime_field) { | |
| 12731 | 11 | uint f_length = 0; | |
| 12732 | 11 | enum enum_mysql_timestamp_type t_type = MYSQL_TIMESTAMP_DATE; | |
| 12733 | |||
| 12734 |
2/3✓ Branch 0 taken 4 times.
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
|
11 | switch (datetime_field->sql_type) { |
| 12735 | 4 | case MYSQL_TYPE_DATE: | |
| 12736 | case MYSQL_TYPE_NEWDATE: | ||
| 12737 | 4 | f_length = MAX_DATE_WIDTH; // "0000-00-00"; | |
| 12738 | 4 | t_type = MYSQL_TIMESTAMP_DATE; | |
| 12739 | 4 | break; | |
| 12740 | 7 | case MYSQL_TYPE_DATETIME: | |
| 12741 | case MYSQL_TYPE_DATETIME2: | ||
| 12742 | 7 | f_length = MAX_DATETIME_WIDTH; // "0000-00-00 00:00:00"; | |
| 12743 | 7 | t_type = MYSQL_TIMESTAMP_DATETIME; | |
| 12744 | 7 | break; | |
| 12745 | ✗ | default: | |
| 12746 | ✗ | assert(false); // Should not get here. | |
| 12747 | } | ||
| 12748 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
11 | return make_truncated_value_warning( |
| 12749 | thd, Sql_condition::SL_WARNING, | ||
| 12750 | 22 | ErrConvString(my_zero_datetime6, f_length), t_type, | |
| 12751 | 22 | datetime_field->field_name); | |
| 12752 | } | ||
| 12753 | |||
| 12754 | /* | ||
| 12755 | Manages enabling/disabling of indexes for ALTER TABLE | ||
| 12756 | |||
| 12757 | SYNOPSIS | ||
| 12758 | alter_table_manage_keys() | ||
| 12759 | table Target table | ||
| 12760 | indexes_were_disabled Whether the indexes of the from table | ||
| 12761 | were disabled | ||
| 12762 | keys_onoff ENABLE | DISABLE | LEAVE_AS_IS | ||
| 12763 | |||
| 12764 | RETURN VALUES | ||
| 12765 | false OK | ||
| 12766 | true Error | ||
| 12767 | */ | ||
| 12768 | |||
| 12769 | 20493 | static bool alter_table_manage_keys( | |
| 12770 | THD *thd, TABLE *table, int indexes_were_disabled, | ||
| 12771 | Alter_info::enum_enable_or_disable keys_onoff) { | ||
| 12772 | 20493 | int error = 0; | |
| 12773 |
1/2✓ Branch 0 taken 20493 times.
✗ Branch 1 not taken.
|
20493 | DBUG_TRACE; |
| 12774 |
3/8✓ Branch 0 taken 20493 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20493 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 20493 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
20493 | DBUG_PRINT("enter", ("table=%p were_disabled=%d on_off=%d", table, |
| 12775 | indexes_were_disabled, keys_onoff)); | ||
| 12776 | |||
| 12777 |
3/4✓ Branch 0 taken 8 times.
✓ Branch 1 taken 20471 times.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
|
20493 | switch (keys_onoff) { |
| 12778 | 8 | case Alter_info::ENABLE: | |
| 12779 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | error = table->file->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); |
| 12780 | 8 | break; | |
| 12781 | 20471 | case Alter_info::LEAVE_AS_IS: | |
| 12782 |
2/2✓ Branch 0 taken 20467 times.
✓ Branch 1 taken 4 times.
|
20471 | if (!indexes_were_disabled) break; |
| 12783 | /* fall-through: disabled indexes */ | ||
| 12784 | [[fallthrough]]; | ||
| 12785 | case Alter_info::DISABLE: | ||
| 12786 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | error = table->file->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); |
| 12787 | } | ||
| 12788 | |||
| 12789 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20493 times.
|
20493 | if (error == HA_ERR_WRONG_COMMAND) { |
| 12790 | ✗ | push_warning_printf(thd, Sql_condition::SL_NOTE, ER_ILLEGAL_HA, | |
| 12791 | ✗ | ER_THD(thd, ER_ILLEGAL_HA), table->s->table_name.str); | |
| 12792 | ✗ | error = 0; | |
| 12793 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20493 times.
|
20493 | } else if (error) |
| 12794 | ✗ | table->file->print_error(error, MYF(0)); | |
| 12795 | |||
| 12796 | 20493 | return error; | |
| 12797 | 20493 | } | |
| 12798 | |||
| 12799 | /** | ||
| 12800 | Check if the pending ALTER TABLE operations support the in-place | ||
| 12801 | algorithm based on restrictions in the SQL layer or given the | ||
| 12802 | nature of the operations themselves. If in-place isn't supported, | ||
| 12803 | it won't be necessary to check with the storage engine. | ||
| 12804 | |||
| 12805 | @param table The original TABLE. | ||
| 12806 | @param create_info Information from the parsing phase about new | ||
| 12807 | table properties. | ||
| 12808 | @param alter_info Data related to detected changes. | ||
| 12809 | |||
| 12810 | @return false In-place is possible, check with storage engine. | ||
| 12811 | @return true Incompatible operations, must use table copy. | ||
| 12812 | */ | ||
| 12813 | |||
| 12814 | 88231 | static bool is_inplace_alter_impossible(TABLE *table, | |
| 12815 | HA_CREATE_INFO *create_info, | ||
| 12816 | const Alter_info *alter_info) { | ||
| 12817 |
1/2✓ Branch 0 taken 88231 times.
✗ Branch 1 not taken.
|
88231 | DBUG_TRACE; |
| 12818 | |||
| 12819 | /* At the moment we can't handle altering temporary tables without a copy. */ | ||
| 12820 |
2/2✓ Branch 0 taken 1164 times.
✓ Branch 1 taken 87067 times.
|
88231 | if (table->s->tmp_table) return true; |
| 12821 | |||
| 12822 | /* | ||
| 12823 | For the ALTER TABLE tbl_name ORDER BY ... we always use copy | ||
| 12824 | algorithm. In theory, this operation can be done in-place by some | ||
| 12825 | engine, but since a) no current engine does this and b) our current | ||
| 12826 | API lacks infrastructure for passing information about table ordering | ||
| 12827 | to storage engine we simply always do copy now. | ||
| 12828 | |||
| 12829 | ENABLE/DISABLE KEYS is a MyISAM/Heap specific operation that is | ||
| 12830 | not supported for in-place in combination with other operations. | ||
| 12831 | Alone, it will be done by simple_rename_or_index_change(). | ||
| 12832 | |||
| 12833 | Stored generated columns are evaluated in server, thus can't be | ||
| 12834 | added/changed inplace. | ||
| 12835 | */ | ||
| 12836 |
2/2✓ Branch 0 taken 83 times.
✓ Branch 1 taken 86984 times.
|
87067 | if (alter_info->flags & |
| 12837 | (Alter_info::ALTER_ORDER | Alter_info::ALTER_KEYS_ONOFF)) | ||
| 12838 | 83 | return true; | |
| 12839 | |||
| 12840 | /* | ||
| 12841 | Check constraints are evaluated in the server, if any check constraint | ||
| 12842 | (re-)evaluation is required then it can't be added/enforced inplace. | ||
| 12843 | */ | ||
| 12844 |
3/4✓ Branch 0 taken 86984 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 124 times.
✓ Branch 3 taken 86860 times.
|
86984 | if (is_any_check_constraints_evaluation_required(alter_info)) return true; |
| 12845 | |||
| 12846 | /* | ||
| 12847 | If the table engine is changed explicitly (using ENGINE clause) | ||
| 12848 | or implicitly (e.g. when non-partitioned table becomes | ||
| 12849 | partitioned) a regular alter table (copy) needs to be | ||
| 12850 | performed. | ||
| 12851 | */ | ||
| 12852 |
3/4✓ Branch 0 taken 86860 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 826 times.
✓ Branch 3 taken 86034 times.
|
86860 | if (create_info->db_type != table->s->db_type()) return true; |
| 12853 | |||
| 12854 | /* | ||
| 12855 | There was a bug prior to mysql-4.0.25. Number of null fields was | ||
| 12856 | calculated incorrectly. As a result frm and data files gets out of | ||
| 12857 | sync after fast alter table. There is no way to determine by which | ||
| 12858 | mysql version (in 4.0 and 4.1 branches) table was created, thus we | ||
| 12859 | disable fast alter table for all tables created by mysql versions | ||
| 12860 | prior to 5.0 branch. | ||
| 12861 | See BUG#6236. | ||
| 12862 | */ | ||
| 12863 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 86034 times.
|
86034 | if (!table->s->mysql_version) return true; |
| 12864 | |||
| 12865 | /* | ||
| 12866 | If we are changing the SRID modifier of a column, we must do a COPY. | ||
| 12867 | But not if we are changing to the NULL SRID. In that case, we can do it | ||
| 12868 | inplace (only metadata change, and no verification needed). | ||
| 12869 | */ | ||
| 12870 |
5/8✓ Branch 0 taken 86034 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 86034 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1034718 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 948724 times.
✓ Branch 7 taken 85994 times.
|
1034718 | for (const Create_field &new_field_def : alter_info->create_list) { |
| 12871 |
4/4✓ Branch 0 taken 918006 times.
✓ Branch 1 taken 30718 times.
✓ Branch 2 taken 663 times.
✓ Branch 3 taken 948061 times.
|
1866730 | if (new_field_def.field != nullptr && |
| 12872 |
3/4✓ Branch 0 taken 918006 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 663 times.
✓ Branch 3 taken 917343 times.
|
918006 | new_field_def.field->type() == MYSQL_TYPE_GEOMETRY) { |
| 12873 | const Field_geom *field_geom = | ||
| 12874 | 663 | down_cast<const Field_geom *>(new_field_def.field); | |
| 12875 | |||
| 12876 |
6/6✓ Branch 0 taken 48 times.
✓ Branch 1 taken 615 times.
✓ Branch 2 taken 40 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 40 times.
✓ Branch 5 taken 623 times.
|
711 | if (field_geom->get_srid() != new_field_def.m_srid && |
| 12877 | 48 | new_field_def.m_srid.has_value()) | |
| 12878 | 40 | return true; | |
| 12879 | } | ||
| 12880 | } | ||
| 12881 | 85994 | return false; | |
| 12882 | 88231 | } | |
| 12883 | |||
| 12884 | /** | ||
| 12885 | Add MDL requests for exclusive lock on tables referenced by the | ||
| 12886 | foreign keys to be dropped by ALTER TABLE operation. Also add | ||
| 12887 | the referenced table names to the foreign key invalidator, | ||
| 12888 | to be used at a later stage to invalidate the dd::Table objects. | ||
| 12889 | |||
| 12890 | @param thd Thread handle. | ||
| 12891 | @param alter_info Alter_info object with the list of FKs | ||
| 12892 | to be dropped. | ||
| 12893 | @param table_def dd::Table describing the table before | ||
| 12894 | ALTER operation. | ||
| 12895 | @param hton Handlerton for table's storage engine. | ||
| 12896 | @param[in,out] mdl_requests List to which MDL requests are to be added. | ||
| 12897 | @param[in,out] fk_invalidator Object keeping track of which dd::Table | ||
| 12898 | objects to invalidate. | ||
| 12899 | |||
| 12900 | @retval operation outcome, false if no error. | ||
| 12901 | */ | ||
| 12902 | 75156 | static bool collect_fk_parents_for_dropped_fks( | |
| 12903 | THD *thd, const Alter_info *alter_info, const dd::Table *table_def, | ||
| 12904 | handlerton *hton, MDL_request_list *mdl_requests, | ||
| 12905 | Foreign_key_parents_invalidator *fk_invalidator) { | ||
| 12906 |
2/2✓ Branch 0 taken 9634 times.
✓ Branch 1 taken 75156 times.
|
84790 | for (const Alter_drop *drop : alter_info->drop_list) { |
| 12907 |
2/2✓ Branch 0 taken 63 times.
✓ Branch 1 taken 9571 times.
|
9634 | if (drop->type == Alter_drop::FOREIGN_KEY) { |
| 12908 |
6/10✓ Branch 0 taken 63 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 63 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 63 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 63 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 63 times.
✓ Branch 9 taken 4 times.
|
67 | for (const dd::Foreign_key *fk : table_def->foreign_keys()) { |
| 12909 |
2/4✓ Branch 0 taken 63 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 63 times.
✗ Branch 3 not taken.
|
63 | if (my_strcasecmp(system_charset_info, drop->name, |
| 12910 |
2/2✓ Branch 0 taken 59 times.
✓ Branch 1 taken 4 times.
|
63 | fk->name().c_str()) == 0) { |
| 12911 | char buff_db[NAME_LEN + 1]; | ||
| 12912 | char buff_table[NAME_LEN + 1]; | ||
| 12913 |
1/2✓ Branch 0 taken 59 times.
✗ Branch 1 not taken.
|
59 | my_stpncpy(buff_db, fk->referenced_table_schema_name().c_str(), |
| 12914 | NAME_LEN); | ||
| 12915 |
1/2✓ Branch 0 taken 59 times.
✗ Branch 1 not taken.
|
59 | my_stpncpy(buff_table, fk->referenced_table_name().c_str(), NAME_LEN); |
| 12916 | |||
| 12917 | /* | ||
| 12918 | In lower-case-table-names == 2 mode we store original versions | ||
| 12919 | of table and db names in the data-dictionary. Hence they need | ||
| 12920 | to be lowercased to produce correct MDL key for them and for | ||
| 12921 | other uses. | ||
| 12922 | */ | ||
| 12923 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 59 times.
|
59 | if (lower_case_table_names == 2) { |
| 12924 | ✗ | my_casedn_str(system_charset_info, buff_db); | |
| 12925 | ✗ | my_casedn_str(system_charset_info, buff_table); | |
| 12926 | } | ||
| 12927 | |||
| 12928 |
1/2✓ Branch 0 taken 59 times.
✗ Branch 1 not taken.
|
59 | MDL_request *mdl_request = new (thd->mem_root) MDL_request; |
| 12929 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 59 times.
|
59 | if (mdl_request == nullptr) return true; |
| 12930 | |||
| 12931 |
1/2✓ Branch 0 taken 59 times.
✗ Branch 1 not taken.
|
59 | MDL_REQUEST_INIT(mdl_request, MDL_key::TABLE, buff_db, buff_table, |
| 12932 | MDL_EXCLUSIVE, MDL_STATEMENT); | ||
| 12933 | |||
| 12934 |
1/2✓ Branch 0 taken 59 times.
✗ Branch 1 not taken.
|
59 | mdl_requests->push_front(mdl_request); |
| 12935 | |||
| 12936 |
1/2✓ Branch 0 taken 59 times.
✗ Branch 1 not taken.
|
59 | mdl_request = new (thd->mem_root) MDL_request; |
| 12937 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 59 times.
|
59 | if (mdl_request == nullptr) return true; |
| 12938 | |||
| 12939 |
1/2✓ Branch 0 taken 59 times.
✗ Branch 1 not taken.
|
59 | MDL_REQUEST_INIT(mdl_request, MDL_key::SCHEMA, buff_db, "", |
| 12940 | MDL_INTENTION_EXCLUSIVE, MDL_STATEMENT); | ||
| 12941 | |||
| 12942 |
1/2✓ Branch 0 taken 59 times.
✗ Branch 1 not taken.
|
59 | mdl_requests->push_front(mdl_request); |
| 12943 | |||
| 12944 |
1/2✓ Branch 0 taken 59 times.
✗ Branch 1 not taken.
|
59 | fk_invalidator->add(buff_db, buff_table, hton); |
| 12945 | 59 | break; | |
| 12946 | } | ||
| 12947 | } | ||
| 12948 | } | ||
| 12949 | } | ||
| 12950 | 75156 | return false; | |
| 12951 | } | ||
| 12952 | |||
| 12953 | /** | ||
| 12954 | Acquire exclusive metadata locks on tables which definitions need to | ||
| 12955 | be updated or invalidated due to foreign keys created or dropped as | ||
| 12956 | result of complex ALTER TABLE operation. | ||
| 12957 | Also add the referenced table names for the FKs created/dropped to the | ||
| 12958 | foreign key invalidator, to be used at a later stage to invalidate the | ||
| 12959 | dd::Table objects. | ||
| 12960 | |||
| 12961 | @param thd Thread handle. | ||
| 12962 | @param table_list Table list element for table being ALTERed. | ||
| 12963 | @param old_table_def Old table definition of table being ALTERed. | ||
| 12964 | @param alter_ctx ALTER TABLE operation context. | ||
| 12965 | @param alter_info Alter_info object with the lists of FKs | ||
| 12966 | to be added or dropped. | ||
| 12967 | @param old_hton Table's old SE. | ||
| 12968 | @param new_hton Table's new SE. | ||
| 12969 | @param[in,out] fk_invalidator Object keeping track of which dd::Table | ||
| 12970 | objects to invalidate. | ||
| 12971 | |||
| 12972 | @retval operation outcome, false if no error. | ||
| 12973 | */ | ||
| 12974 | 75429 | static bool collect_and_lock_fk_tables_for_complex_alter_table( | |
| 12975 | THD *thd, TABLE_LIST *table_list, const dd::Table *old_table_def, | ||
| 12976 | const Alter_table_ctx *alter_ctx, const Alter_info *alter_info, | ||
| 12977 | handlerton *old_hton, handlerton *new_hton, | ||
| 12978 | Foreign_key_parents_invalidator *fk_invalidator) { | ||
| 12979 |
1/2✓ Branch 0 taken 75429 times.
✗ Branch 1 not taken.
|
75429 | MDL_request_list mdl_requests; |
| 12980 | |||
| 12981 |
2/4✓ Branch 0 taken 75429 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 75429 times.
|
75429 | if (collect_fk_parents_for_new_fks( |
| 12982 | thd, table_list->db, table_list->table_name, alter_info, | ||
| 12983 | MDL_EXCLUSIVE, new_hton, &mdl_requests, fk_invalidator)) | ||
| 12984 | ✗ | return true; | |
| 12985 | |||
| 12986 |
2/2✓ Branch 0 taken 273 times.
✓ Branch 1 taken 75156 times.
|
75429 | if (alter_ctx->is_table_renamed()) { |
| 12987 |
2/4✓ Branch 0 taken 273 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 273 times.
|
273 | if (collect_fk_parents_for_all_fks(thd, old_table_def, old_hton, |
| 12988 | MDL_EXCLUSIVE, &mdl_requests, | ||
| 12989 | fk_invalidator)) | ||
| 12990 | ✗ | return true; | |
| 12991 | } else { | ||
| 12992 |
2/4✓ Branch 0 taken 75156 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 75156 times.
|
75156 | if (collect_fk_parents_for_dropped_fks(thd, alter_info, old_table_def, |
| 12993 | old_hton, &mdl_requests, | ||
| 12994 | fk_invalidator)) | ||
| 12995 | ✗ | return true; | |
| 12996 | } | ||
| 12997 | |||
| 12998 |
2/2✓ Branch 0 taken 803 times.
✓ Branch 1 taken 74626 times.
|
75429 | if (new_hton != old_hton) { |
| 12999 | /* | ||
| 13000 | By changing table's storage engine we might be introducing parent | ||
| 13001 | table for previously orphan foreign keys in the new SE. We need | ||
| 13002 | to lock child tables of such orphan foreign keys. OTOH it is safe | ||
| 13003 | to assume that if SE is changed table can't be parent in any | ||
| 13004 | foreign keys in old SE. | ||
| 13005 | */ | ||
| 13006 |
2/4✓ Branch 0 taken 803 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 803 times.
|
803 | assert(old_table_def->foreign_key_parents().size() == 0); |
| 13007 | |||
| 13008 |
2/4✓ Branch 0 taken 803 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 803 times.
|
803 | if (collect_fk_children(thd, table_list->db, table_list->table_name, |
| 13009 | new_hton, MDL_EXCLUSIVE, &mdl_requests)) | ||
| 13010 | ✗ | return true; | |
| 13011 | } else { | ||
| 13012 |
2/4✓ Branch 0 taken 74626 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 74626 times.
|
74626 | if (collect_fk_children(thd, old_table_def, MDL_EXCLUSIVE, &mdl_requests)) |
| 13013 | ✗ | return true; | |
| 13014 | } | ||
| 13015 | |||
| 13016 |
2/2✓ Branch 0 taken 273 times.
✓ Branch 1 taken 75156 times.
|
75429 | if (alter_ctx->is_table_renamed()) { |
| 13017 |
2/4✓ Branch 0 taken 273 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 273 times.
|
273 | if (collect_fk_children(thd, alter_ctx->new_db, alter_ctx->new_alias, |
| 13018 | new_hton, MDL_EXCLUSIVE, &mdl_requests)) | ||
| 13019 | ✗ | return true; | |
| 13020 | } | ||
| 13021 | |||
| 13022 |
4/4✓ Branch 0 taken 313 times.
✓ Branch 1 taken 75116 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 75428 times.
|
75742 | if (!mdl_requests.is_empty() && |
| 13023 |
3/4✓ Branch 0 taken 313 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 312 times.
|
313 | thd->mdl_context.acquire_locks(&mdl_requests, |
| 13024 | thd->variables.lock_wait_timeout)) | ||
| 13025 | 1 | return true; | |
| 13026 | |||
| 13027 | 75428 | return false; | |
| 13028 | } | ||
| 13029 | |||
| 13030 | /** | ||
| 13031 | Update referenced table names and the unique constraint name for FKs | ||
| 13032 | affected by complex ALTER TABLE operation. | ||
| 13033 | |||
| 13034 | @param thd Thread handle. | ||
| 13035 | @param table_list Table list element for table being ALTERed. | ||
| 13036 | @param alter_ctx ALTER TABLE operation context. | ||
| 13037 | @param alter_info Alter_info describing ALTER TABLE, specifically | ||
| 13038 | containing information about columns being renamed. | ||
| 13039 | @param new_hton Table's new SE. | ||
| 13040 | @param fk_invalidator Object keeping track of which dd::Table | ||
| 13041 | objects to invalidate. Used to filter out | ||
| 13042 | which FK parents should have their FK parent | ||
| 13043 | information reloaded. | ||
| 13044 | |||
| 13045 | @retval operation outcome, false if no error. | ||
| 13046 | */ | ||
| 13047 | 63716 | static bool adjust_fks_for_complex_alter_table( | |
| 13048 | THD *thd, TABLE_LIST *table_list, Alter_table_ctx *alter_ctx, | ||
| 13049 | Alter_info *alter_info, handlerton *new_hton, | ||
| 13050 | const Foreign_key_parents_invalidator *fk_invalidator) { | ||
| 13051 |
2/2✓ Branch 0 taken 3461 times.
✓ Branch 1 taken 60255 times.
|
63716 | if (!(new_hton->flags & HTON_SUPPORTS_FOREIGN_KEYS)) return false; |
| 13052 | |||
| 13053 | 60255 | const dd::Table *new_table = nullptr; | |
| 13054 |
4/8✓ Branch 0 taken 60255 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 60255 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 60255 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 60255 times.
|
60255 | if (thd->dd_client()->acquire(alter_ctx->new_db, alter_ctx->new_alias, |
| 13055 | &new_table)) | ||
| 13056 | ✗ | return true; | |
| 13057 | |||
| 13058 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 60255 times.
|
60255 | assert(new_table != nullptr); |
| 13059 | |||
| 13060 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 60255 times.
|
60255 | if (adjust_fk_children_after_parent_def_change( |
| 13061 | thd, | ||
| 13062 | /* | ||
| 13063 | For consistency with check_fk_children_after_parent_def_change(), | ||
| 13064 | allow charset discrepancies between child and parent columns in | ||
| 13065 | FOREIGN_KEY_CHECKS=0 mode. | ||
| 13066 | */ | ||
| 13067 |
1/2✓ Branch 0 taken 60255 times.
✗ Branch 1 not taken.
|
60255 | !(thd->variables.option_bits & OPTION_NO_FOREIGN_KEY_CHECKS), |
| 13068 | table_list->db, table_list->table_name, new_hton, new_table, | ||
| 13069 | alter_info, true)) | ||
| 13070 | ✗ | return true; | |
| 13071 | |||
| 13072 |
2/2✓ Branch 0 taken 265 times.
✓ Branch 1 taken 59990 times.
|
60255 | if (alter_ctx->is_table_renamed()) { |
| 13073 |
2/4✓ Branch 0 taken 265 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 265 times.
|
265 | if (adjust_fk_children_after_parent_rename( |
| 13074 | thd, table_list->db, table_list->table_name, new_hton, | ||
| 13075 | alter_ctx->new_db, alter_ctx->new_alias)) | ||
| 13076 | ✗ | return true; | |
| 13077 | |||
| 13078 |
2/4✓ Branch 0 taken 265 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 265 times.
|
265 | if (adjust_fk_children_after_parent_def_change( |
| 13079 | thd, alter_ctx->new_db, alter_ctx->new_alias, new_hton, new_table, | ||
| 13080 | nullptr)) | ||
| 13081 | ✗ | return true; | |
| 13082 | } | ||
| 13083 | |||
| 13084 |
1/2✓ Branch 0 taken 60255 times.
✗ Branch 1 not taken.
|
60255 | return adjust_fk_parents(thd, alter_ctx->new_db, alter_ctx->new_alias, true, |
| 13085 | 60255 | fk_invalidator); | |
| 13086 | } | ||
| 13087 | |||
| 13088 | /** | ||
| 13089 | Add appropriate MDL requests on names of foreign keys on the table | ||
| 13090 | to be renamed to the requests list. | ||
| 13091 | |||
| 13092 | @param thd Thread handle. | ||
| 13093 | @param db Table's old schema. | ||
| 13094 | @param table_name Table's old name. | ||
| 13095 | @param table_def Table definition of table being RENAMEd. | ||
| 13096 | @param hton Table's storage engine. | ||
| 13097 | @param new_db Table's new schema. | ||
| 13098 | @param new_table_name Table's new name. | ||
| 13099 | @param[in,out] mdl_requests List to which MDL requests need to be | ||
| 13100 | added. | ||
| 13101 | |||
| 13102 | @retval operation outcome, false if no error. | ||
| 13103 | */ | ||
| 13104 | |||
| 13105 | 2106 | static bool collect_fk_names_for_rename_table( | |
| 13106 | THD *thd, const char *db, const char *table_name, | ||
| 13107 | const dd::Table *table_def, handlerton *hton, const char *new_db, | ||
| 13108 | const char *new_table_name, MDL_request_list *mdl_requests) | ||
| 13109 | |||
| 13110 | { | ||
| 13111 | bool is_table_renamed = | ||
| 13112 |
1/2✓ Branch 0 taken 2106 times.
✗ Branch 1 not taken.
|
2106 | (my_strcasecmp(table_alias_charset, table_name, new_table_name) != 0); |
| 13113 |
1/2✓ Branch 0 taken 2106 times.
✗ Branch 1 not taken.
|
2106 | bool is_db_changed = (my_strcasecmp(table_alias_charset, db, new_db) != 0); |
| 13114 | |||
| 13115 | char old_table_name_norm[NAME_LEN + 1]; | ||
| 13116 |
1/2✓ Branch 0 taken 2106 times.
✗ Branch 1 not taken.
|
2106 | strmake(old_table_name_norm, table_name, NAME_LEN); |
| 13117 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2106 times.
|
2106 | if (lower_case_table_names == 2) |
| 13118 | ✗ | my_casedn_str(system_charset_info, old_table_name_norm); | |
| 13119 | char new_table_name_lc[NAME_LEN + 1]; | ||
| 13120 |
1/2✓ Branch 0 taken 2106 times.
✗ Branch 1 not taken.
|
2106 | strmake(new_table_name_lc, new_table_name, NAME_LEN); |
| 13121 | /* | ||
| 13122 | Unless new table name in lower case already we need to lowercase | ||
| 13123 | it, so it can be used to construct lowercased version of FK name | ||
| 13124 | for acquiring metadata lock. | ||
| 13125 | */ | ||
| 13126 |
2/2✓ Branch 0 taken 1980 times.
✓ Branch 1 taken 126 times.
|
2106 | if (lower_case_table_names != 1) |
| 13127 |
1/2✓ Branch 0 taken 1980 times.
✗ Branch 1 not taken.
|
1980 | my_casedn_str(system_charset_info, new_table_name_lc); |
| 13128 | 2106 | size_t old_table_name_norm_len = strlen(old_table_name_norm); | |
| 13129 | |||
| 13130 |
6/10✓ Branch 0 taken 2106 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2106 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2106 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 28 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 28 times.
✓ Branch 9 taken 2106 times.
|
2134 | for (const dd::Foreign_key *fk : table_def->foreign_keys()) { |
| 13131 | /* | ||
| 13132 | Since foreign key names are case-insensitive we need to lowercase | ||
| 13133 | them before passing to MDL subsystem. | ||
| 13134 | */ | ||
| 13135 | char fk_name[NAME_LEN + 1]; | ||
| 13136 |
2/4✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
|
28 | strmake(fk_name, fk->name().c_str(), NAME_LEN); |
| 13137 |
1/2✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
|
28 | my_casedn_str(system_charset_info, fk_name); |
| 13138 | |||
| 13139 |
1/2✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
|
28 | MDL_request *mdl_request = new (thd->mem_root) MDL_request; |
| 13140 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
|
28 | if (mdl_request == nullptr) return true; |
| 13141 | |||
| 13142 |
1/2✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
|
28 | MDL_REQUEST_INIT(mdl_request, MDL_key::FOREIGN_KEY, db, fk_name, |
| 13143 | MDL_EXCLUSIVE, MDL_STATEMENT); | ||
| 13144 | |||
| 13145 |
1/2✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
|
28 | mdl_requests->push_front(mdl_request); |
| 13146 | |||
| 13147 |
3/4✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
✓ Branch 3 taken 1 times.
|
56 | if (is_table_renamed && |
| 13148 |
3/4✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
✓ Branch 3 taken 1 times.
|
28 | dd::is_generated_foreign_key_name(old_table_name_norm, |
| 13149 | old_table_name_norm_len, hton, *fk)) { | ||
| 13150 | char new_fk_name[NAME_LEN + 1]; | ||
| 13151 | |||
| 13152 | /* | ||
| 13153 | Copy <SE-specific or default FK name suffix><number> part. | ||
| 13154 | Here we truncate generated name if it is too long. This is sufficient | ||
| 13155 | for MDL purposes. Error will be reported later in this case. | ||
| 13156 | */ | ||
| 13157 |
1/2✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
|
27 | strxnmov(new_fk_name, NAME_LEN, new_table_name_lc, |
| 13158 |
1/2✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
|
27 | fk->name().c_str() + old_table_name_norm_len, NullS); |
| 13159 | |||
| 13160 |
1/2✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
|
27 | MDL_request *mdl_request2 = new (thd->mem_root) MDL_request; |
| 13161 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
|
27 | if (mdl_request2 == nullptr) return true; |
| 13162 | |||
| 13163 |
1/2✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
|
27 | MDL_REQUEST_INIT(mdl_request2, MDL_key::FOREIGN_KEY, new_db, new_fk_name, |
| 13164 | MDL_EXCLUSIVE, MDL_STATEMENT); | ||
| 13165 | |||
| 13166 |
1/2✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
|
27 | mdl_requests->push_front(mdl_request2); |
| 13167 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | } else if (is_db_changed) { |
| 13168 | ✗ | MDL_request *mdl_request2 = new (thd->mem_root) MDL_request; | |
| 13169 | ✗ | if (mdl_request2 == nullptr) return true; | |
| 13170 | |||
| 13171 | ✗ | MDL_REQUEST_INIT(mdl_request2, MDL_key::FOREIGN_KEY, new_db, fk_name, | |
| 13172 | MDL_EXCLUSIVE, MDL_STATEMENT); | ||
| 13173 | |||
| 13174 | ✗ | mdl_requests->push_front(mdl_request2); | |
| 13175 | } | ||
| 13176 | } | ||
| 13177 | |||
| 13178 | 2106 | return false; | |
| 13179 | } | ||
| 13180 | |||
| 13181 | /** | ||
| 13182 | Check if complex ALTER TABLE with RENAME clause results in foreign key | ||
| 13183 | names conflicts. | ||
| 13184 | |||
| 13185 | @param thd Thread handle. | ||
| 13186 | @param table_list Table list element for table altered. | ||
| 13187 | @param table_def dd::Table object describing new version of | ||
| 13188 | table prior to rename operation. | ||
| 13189 | @param hton Table's storage engine. | ||
| 13190 | @param new_schema dd::Schema object for target schema. | ||
| 13191 | @param alter_ctx ALTER TABLE operation context. | ||
| 13192 | |||
| 13193 | @retval True if error (e.g. due to foreign key name conflict), | ||
| 13194 | false - otherwise. | ||
| 13195 | */ | ||
| 13196 | |||
| 13197 | 267 | static bool check_fk_names_before_rename(THD *thd, TABLE_LIST *table_list, | |
| 13198 | const dd::Table &table_def, | ||
| 13199 | handlerton *hton, | ||
| 13200 | const dd::Schema &new_schema, | ||
| 13201 | const Alter_table_ctx &alter_ctx) { | ||
| 13202 |
6/10✓ Branch 0 taken 267 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 267 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 267 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 267 times.
|
269 | for (const dd::Foreign_key *fk : table_def.foreign_keys()) { |
| 13203 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
4 | if (alter_ctx.is_table_name_changed() && |
| 13204 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | dd::is_generated_foreign_key_name( |
| 13205 | table_list->table_name, table_list->table_name_length, hton, *fk)) { | ||
| 13206 | // We reserve extra NAME_LEN to ensure that new name fits. | ||
| 13207 | char new_fk_name[NAME_LEN + NAME_LEN + 1]; | ||
| 13208 | |||
| 13209 | /* | ||
| 13210 | Construct new name by copying <FK name suffix><number> suffix | ||
| 13211 | from the old one. | ||
| 13212 | */ | ||
| 13213 | 2 | strxnmov(new_fk_name, sizeof(new_fk_name) - 1, alter_ctx.new_name, | |
| 13214 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | fk->name().c_str() + table_list->table_name_length, NullS); |
| 13215 | |||
| 13216 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
2 | if (check_string_char_length(to_lex_cstring(new_fk_name), "", |
| 13217 | NAME_CHAR_LEN, system_charset_info, | ||
| 13218 | true /* no error */)) { | ||
| 13219 | ✗ | my_error(ER_TOO_LONG_IDENT, MYF(0), new_fk_name); | |
| 13220 | ✗ | return true; | |
| 13221 | } | ||
| 13222 | |||
| 13223 | bool exists; | ||
| 13224 |
3/6✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
|
2 | if (thd->dd_client()->check_foreign_key_exists(new_schema, new_fk_name, |
| 13225 | &exists)) | ||
| 13226 | ✗ | return true; | |
| 13227 | |||
| 13228 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (exists) { |
| 13229 | ✗ | my_error(ER_FK_DUP_NAME, MYF(0), new_fk_name); | |
| 13230 | ✗ | return true; | |
| 13231 | } | ||
| 13232 | ✗ | } else if (alter_ctx.is_database_changed()) { | |
| 13233 | bool exists; | ||
| 13234 | ✗ | if (thd->dd_client()->check_foreign_key_exists(new_schema, fk->name(), | |
| 13235 | &exists)) | ||
| 13236 | ✗ | return true; | |
| 13237 | |||
| 13238 | ✗ | if (exists) { | |
| 13239 | ✗ | my_error(ER_FK_DUP_NAME, MYF(0), fk->name().c_str()); | |
| 13240 | ✗ | return true; | |
| 13241 | } | ||
| 13242 | } | ||
| 13243 | } | ||
| 13244 | |||
| 13245 | 267 | return false; | |
| 13246 | } | ||
| 13247 | |||
| 13248 | /** | ||
| 13249 | Check if a table is empty, i.e., it has no rows. | ||
| 13250 | |||
| 13251 | @param[in] table The table. | ||
| 13252 | @param[out] is_empty Set to true if the table is empty. | ||
| 13253 | |||
| 13254 | @retval false Success. | ||
| 13255 | @retval true An error occurred (and has been reported with print_error). | ||
| 13256 | */ | ||
| 13257 | 109 | static bool table_is_empty(TABLE *table, bool *is_empty) { | |
| 13258 | 109 | *is_empty = false; | |
| 13259 | 109 | int error = 0; | |
| 13260 |
1/2✓ Branch 0 taken 109 times.
✗ Branch 1 not taken.
|
109 | if (!(error = table->file->ha_rnd_init(true))) { |
| 13261 | do { | ||
| 13262 | 109 | error = table->file->ha_rnd_next(table->record[0]); | |
| 13263 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 109 times.
|
109 | } while (error == HA_ERR_RECORD_DELETED); |
| 13264 |
2/2✓ Branch 0 taken 97 times.
✓ Branch 1 taken 12 times.
|
109 | if (error == HA_ERR_END_OF_FILE) *is_empty = true; |
| 13265 | } | ||
| 13266 |
3/4✓ Branch 0 taken 97 times.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 97 times.
|
109 | if (error && error != HA_ERR_END_OF_FILE) { |
| 13267 | ✗ | table->file->print_error(error, MYF(0)); | |
| 13268 | ✗ | table->file->ha_rnd_end(); | |
| 13269 | ✗ | return true; | |
| 13270 | } | ||
| 13271 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 109 times.
|
109 | if ((error = table->file->ha_rnd_end())) { |
| 13272 | ✗ | table->file->print_error(error, MYF(0)); | |
| 13273 | ✗ | return true; | |
| 13274 | } | ||
| 13275 | 109 | return false; | |
| 13276 | } | ||
| 13277 | |||
| 13278 | /** | ||
| 13279 | * Unloads table from secondary engine if SECONDARY_ENGINE = NULL. | ||
| 13280 | * | ||
| 13281 | * @param thd Thread handler. | ||
| 13282 | * @param table Table opened in primary storage engine. | ||
| 13283 | * @param create_info Information from the parsing phase about new | ||
| 13284 | * table properties. | ||
| 13285 | * @param old_table_def Definition of table before the alter statement. | ||
| 13286 | * | ||
| 13287 | * @return True if error, false otherwise. | ||
| 13288 | */ | ||
| 13289 | 79143 | static bool remove_secondary_engine(THD *thd, const TABLE_LIST &table, | |
| 13290 | const HA_CREATE_INFO &create_info, | ||
| 13291 | const dd::Table *old_table_def) { | ||
| 13292 | // Nothing to do if no secondary engine defined for the table. | ||
| 13293 |
2/2✓ Branch 0 taken 79115 times.
✓ Branch 1 taken 28 times.
|
79143 | if (table.table->s->secondary_engine.str == nullptr) return false; |
| 13294 | |||
| 13295 | // Check if SECONDARY_ENGINE = NULL has been set in ALTER TABLE. | ||
| 13296 | 28 | const bool is_null = | |
| 13297 |
1/2✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
|
56 | create_info.used_fields & HA_CREATE_USED_SECONDARY_ENGINE && |
| 13298 |
1/2✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
|
28 | create_info.secondary_engine.str == nullptr; |
| 13299 | |||
| 13300 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
|
28 | if (!is_null) return false; |
| 13301 | |||
| 13302 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
|
28 | if (thd->mdl_context.upgrade_shared_lock(table.table->mdl_ticket, |
| 13303 | MDL_EXCLUSIVE, | ||
| 13304 | thd->variables.lock_wait_timeout)) | ||
| 13305 | ✗ | return true; | |
| 13306 | |||
| 13307 | 28 | return secondary_engine_unload_table(thd, table.db, table.table_name, | |
| 13308 | 28 | *old_table_def, false); | |
| 13309 | } | ||
| 13310 | |||
| 13311 | /** | ||
| 13312 | Perform in-place alter table. | ||
| 13313 | |||
| 13314 | @param thd Thread handle. | ||
| 13315 | @param schema Source schema. | ||
| 13316 | @param new_schema Target schema. | ||
| 13317 | @param table_def Table object for the original table. | ||
| 13318 | @param altered_table_def Table object for the new version of the table. | ||
| 13319 | @param table_list TABLE_LIST for the table to change. | ||
| 13320 | @param table The original TABLE. | ||
| 13321 | @param altered_table TABLE object for new version of the table. | ||
| 13322 | @param ha_alter_info Structure describing ALTER TABLE to be carried | ||
| 13323 | out and serving as a storage place for data | ||
| 13324 | used during different phases. | ||
| 13325 | @param inplace_supported Enum describing the locking requirements. | ||
| 13326 | @param alter_ctx ALTER TABLE runtime context. | ||
| 13327 | @param columns A list of columns to be modified. This is needed | ||
| 13328 | for removal/renaming of histogram statistics. | ||
| 13329 | @param fk_key_info Array of FOREIGN_KEY objects describing foreign | ||
| 13330 | keys in new table version. | ||
| 13331 | @param fk_key_count Number of foreign keys in new table version. | ||
| 13332 | @param[out] fk_invalidator Set of parent tables which participate in FKs | ||
| 13333 | together with table being altered and which | ||
| 13334 | entries in DD cache need to be invalidated. | ||
| 13335 | |||
| 13336 | @retval true Error | ||
| 13337 | @retval false Success | ||
| 13338 | |||
| 13339 | @note | ||
| 13340 | If mysql_alter_table does not need to copy the table, it is | ||
| 13341 | either an alter table where the storage engine does not | ||
| 13342 | need to know about the change, only the frm will change, | ||
| 13343 | or the storage engine supports performing the alter table | ||
| 13344 | operation directly, in-place without mysql having to copy | ||
| 13345 | the table. | ||
| 13346 | |||
| 13347 | @note This function frees the TABLE object associated with the new version of | ||
| 13348 | the table and removes the .FRM file for it in case of both success and | ||
| 13349 | failure. | ||
| 13350 | */ | ||
| 13351 | |||
| 13352 | 57770 | static bool mysql_inplace_alter_table( | |
| 13353 | THD *thd, const dd::Schema &schema, const dd::Schema &new_schema, | ||
| 13354 | const dd::Table *table_def, dd::Table *altered_table_def, | ||
| 13355 | TABLE_LIST *table_list, TABLE *table, TABLE *altered_table, | ||
| 13356 | Alter_inplace_info *ha_alter_info, | ||
| 13357 | enum_alter_inplace_result inplace_supported, Alter_table_ctx *alter_ctx, | ||
| 13358 | histograms::columns_set &columns, FOREIGN_KEY *fk_key_info, | ||
| 13359 | uint fk_key_count, Foreign_key_parents_invalidator *fk_invalidator) { | ||
| 13360 |
1/2✓ Branch 0 taken 57770 times.
✗ Branch 1 not taken.
|
57770 | handlerton *db_type = table->s->db_type(); |
| 13361 | 57770 | MDL_ticket *mdl_ticket = table->mdl_ticket; | |
| 13362 | 57770 | Alter_info *alter_info = ha_alter_info->alter_info; | |
| 13363 | 57770 | bool reopen_tables = false; | |
| 13364 | 57770 | bool rollback_needs_dict_cache_reset = false; | |
| 13365 |
1/2✓ Branch 0 taken 57770 times.
✗ Branch 1 not taken.
|
57770 | MDL_request_list mdl_requests; |
| 13366 | |||
| 13367 |
1/2✓ Branch 0 taken 57770 times.
✗ Branch 1 not taken.
|
57770 | DBUG_TRACE; |
| 13368 | |||
| 13369 | /* | ||
| 13370 | Upgrade to EXCLUSIVE lock if: | ||
| 13371 | - This is requested by the storage engine | ||
| 13372 | - Or the storage engine needs exclusive lock for just the prepare | ||
| 13373 | phase | ||
| 13374 | - Or requested by the user | ||
| 13375 | |||
| 13376 | Note that we handle situation when storage engine needs exclusive | ||
| 13377 | lock for prepare phase under LOCK TABLES in the same way as when | ||
| 13378 | exclusive lock is required for duration of the whole statement. | ||
| 13379 | */ | ||
| 13380 |
4/4✓ Branch 0 taken 57764 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 55820 times.
✓ Branch 3 taken 1944 times.
|
57770 | if (inplace_supported == HA_ALTER_INPLACE_EXCLUSIVE_LOCK || |
| 13381 |
2/2✓ Branch 0 taken 45138 times.
✓ Branch 1 taken 10682 times.
|
55820 | ((inplace_supported == HA_ALTER_INPLACE_SHARED_LOCK_AFTER_PREPARE || |
| 13382 | 47082 | inplace_supported == HA_ALTER_INPLACE_NO_LOCK_AFTER_PREPARE) && | |
| 13383 |
2/2✓ Branch 0 taken 47012 times.
✓ Branch 1 taken 70 times.
|
47082 | (thd->locked_tables_mode == LTM_LOCK_TABLES || |
| 13384 |
1/2✓ Branch 0 taken 47012 times.
✗ Branch 1 not taken.
|
47012 | thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES)) || |
| 13385 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 57683 times.
|
57694 | alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_EXCLUSIVE) { |
| 13386 |
2/4✓ Branch 0 taken 87 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 87 times.
|
87 | if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN)) |
| 13387 | ✗ | goto cleanup; | |
| 13388 | /* | ||
| 13389 | Get rid of all TABLE instances belonging to this thread | ||
| 13390 | except one to be used for in-place ALTER TABLE. | ||
| 13391 | |||
| 13392 | This is mostly needed to satisfy InnoDB assumptions/asserts. | ||
| 13393 | */ | ||
| 13394 |
1/2✓ Branch 0 taken 87 times.
✗ Branch 1 not taken.
|
87 | close_all_tables_for_name(thd, table->s, false, table); |
| 13395 | /* | ||
| 13396 | If we are under LOCK TABLES we will need to reopen tables which we | ||
| 13397 | just have closed in case of error. | ||
| 13398 | */ | ||
| 13399 | 87 | reopen_tables = true; | |
| 13400 |
4/4✓ Branch 0 taken 55748 times.
✓ Branch 1 taken 1935 times.
✓ Branch 2 taken 45067 times.
✓ Branch 3 taken 10681 times.
|
57683 | } else if (inplace_supported == HA_ALTER_INPLACE_SHARED_LOCK_AFTER_PREPARE || |
| 13401 | inplace_supported == HA_ALTER_INPLACE_NO_LOCK_AFTER_PREPARE) { | ||
| 13402 | /* | ||
| 13403 | Storage engine has requested exclusive lock only for prepare phase | ||
| 13404 | and we are not under LOCK TABLES. | ||
| 13405 | Don't mark TABLE_SHARE as old in this case, as this won't allow opening | ||
| 13406 | of table by other threads during main phase of in-place ALTER TABLE. | ||
| 13407 | */ | ||
| 13408 |
3/4✓ Branch 0 taken 47002 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 37 times.
✓ Branch 3 taken 46965 times.
|
47002 | if (thd->mdl_context.upgrade_shared_lock(table->mdl_ticket, MDL_EXCLUSIVE, |
| 13409 | thd->variables.lock_wait_timeout)) | ||
| 13410 | 37 | goto cleanup; | |
| 13411 | |||
| 13412 | 46965 | tdc_remove_table(thd, TDC_RT_REMOVE_NOT_OWN_KEEP_SHARE, table->s->db.str, | |
| 13413 |
1/2✓ Branch 0 taken 46965 times.
✗ Branch 1 not taken.
|
46965 | table->s->table_name.str, false); |
| 13414 | } | ||
| 13415 | |||
| 13416 | /* | ||
| 13417 | Upgrade to SHARED_NO_WRITE lock if: | ||
| 13418 | - The storage engine needs writes blocked for the whole duration | ||
| 13419 | - Or this is requested by the user | ||
| 13420 | Note that under LOCK TABLES, we will already have SHARED_NO_READ_WRITE. | ||
| 13421 | */ | ||
| 13422 | 115466 | if ((inplace_supported == HA_ALTER_INPLACE_SHARED_LOCK || | |
| 13423 |
4/6✓ Branch 0 taken 57733 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 57716 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 57733 times.
|
57750 | alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_SHARED) && |
| 13424 |
2/4✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 17 times.
|
17 | thd->mdl_context.upgrade_shared_lock(table->mdl_ticket, |
| 13425 | MDL_SHARED_NO_WRITE, | ||
| 13426 | thd->variables.lock_wait_timeout)) { | ||
| 13427 | ✗ | goto cleanup; | |
| 13428 | } | ||
| 13429 | |||
| 13430 | /* | ||
| 13431 | Acquire locks on names of new foreign keys. INPLACE algorithm creates | ||
| 13432 | the new table definition in the original table's database. | ||
| 13433 | */ | ||
| 13434 |
2/4✓ Branch 0 taken 57733 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 57733 times.
✗ Branch 3 not taken.
|
57733 | if (collect_fk_names_for_new_fks( |
| 13435 | thd, table_list->db, table_list->table_name, alter_info, db_type, | ||
| 13436 | get_fk_max_generated_name_number(table_list->table_name, table_def, | ||
| 13437 | db_type), | ||
| 13438 |
4/6✓ Branch 0 taken 57733 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 161 times.
✓ Branch 3 taken 57572 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 57733 times.
|
115627 | &mdl_requests) || |
| 13439 | 57733 | (alter_ctx->is_table_renamed() && | |
| 13440 |
2/4✓ Branch 0 taken 161 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 161 times.
|
161 | collect_fk_names_for_rename_table( |
| 13441 | thd, table_list->db, table_list->table_name, altered_table_def, | ||
| 13442 | db_type, alter_ctx->new_db, alter_ctx->new_name, &mdl_requests))) | ||
| 13443 | ✗ | goto cleanup; | |
| 13444 | |||
| 13445 |
3/4✓ Branch 0 taken 97 times.
✓ Branch 1 taken 57636 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 57733 times.
|
57830 | if (!mdl_requests.is_empty() && |
| 13446 |
2/4✓ Branch 0 taken 97 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 97 times.
|
97 | thd->mdl_context.acquire_locks(&mdl_requests, |
| 13447 | thd->variables.lock_wait_timeout)) | ||
| 13448 | ✗ | goto cleanup; | |
| 13449 | |||
| 13450 | /* | ||
| 13451 | Check if ALTER TABLE results in any foreign key name conflicts | ||
| 13452 | before starting potentially expensive phases of INPLACE ALTER. | ||
| 13453 | */ | ||
| 13454 |
4/10✓ Branch 0 taken 57733 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 57733 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 54173 times.
✓ Branch 5 taken 3560 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
115466 | if (!dd::get_dictionary()->is_dd_table_name(table_list->db, |
| 13455 |
6/10✓ Branch 0 taken 57733 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 57733 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 57733 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 57726 times.
✓ Branch 7 taken 7 times.
✓ Branch 8 taken 57733 times.
✗ Branch 9 not taken.
|
173192 | table_list->table_name) && |
| 13456 |
2/2✓ Branch 0 taken 54173 times.
✓ Branch 1 taken 3553 times.
|
57726 | (db_type->flags & HTON_SUPPORTS_FOREIGN_KEYS)) { |
| 13457 | 54273 | for (FOREIGN_KEY *fk = fk_key_info + alter_ctx->fk_count; | |
| 13458 |
2/2✓ Branch 0 taken 102 times.
✓ Branch 1 taken 54171 times.
|
54273 | fk < fk_key_info + fk_key_count; ++fk) { |
| 13459 | bool exists; | ||
| 13460 |
3/6✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 102 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 102 times.
|
102 | if (thd->dd_client()->check_foreign_key_exists(schema, fk->name, &exists)) |
| 13461 | 2 | goto cleanup; | |
| 13462 | |||
| 13463 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 100 times.
|
102 | if (exists) { |
| 13464 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | my_error(ER_FK_DUP_NAME, MYF(0), fk->name); |
| 13465 | 2 | goto cleanup; | |
| 13466 | } | ||
| 13467 | } | ||
| 13468 | |||
| 13469 |
3/4✓ Branch 0 taken 160 times.
✓ Branch 1 taken 54011 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 54171 times.
|
54331 | if (alter_ctx->is_table_renamed() && |
| 13470 |
2/4✓ Branch 0 taken 160 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 160 times.
|
160 | check_fk_names_before_rename(thd, table_list, *altered_table_def, |
| 13471 | db_type, new_schema, *alter_ctx)) | ||
| 13472 | ✗ | goto cleanup; | |
| 13473 | } | ||
| 13474 | |||
| 13475 | // It's now safe to take the table level lock. | ||
| 13476 |
3/4✓ Branch 0 taken 57731 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 57728 times.
|
57731 | if (lock_tables(thd, table_list, alter_ctx->tables_opened, 0)) goto cleanup; |
| 13477 | |||
| 13478 |
2/2✓ Branch 0 taken 109 times.
✓ Branch 1 taken 57619 times.
|
57728 | if (alter_ctx->error_if_not_empty) { |
| 13479 | /* | ||
| 13480 | Storage engines should not suggest/support INSTANT algorithm if | ||
| 13481 | error_if_not_empty flag is set. | ||
| 13482 | The problem is that the below check if table is empty is not "instant", | ||
| 13483 | as it might have to traverse through deleted versions of rows on SQL-layer | ||
| 13484 | (e.g. MyISAM) or in SE (e.g. InnoDB). | ||
| 13485 | |||
| 13486 | OTOH for cases when table is empty difference between INSTANT and INPLACE | ||
| 13487 | or COPY algorithms should be negligible. | ||
| 13488 | |||
| 13489 | This limitation might be raised in the future if we will implement support | ||
| 13490 | for quick (i.e. non-traversing) check for table emptiness. | ||
| 13491 | */ | ||
| 13492 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 109 times.
|
109 | assert(inplace_supported != HA_ALTER_INPLACE_INSTANT); |
| 13493 | /* | ||
| 13494 | Operations which set error_if_not_empty flag typically request exclusive | ||
| 13495 | lock during prepare phase, so we don't have to upgrade lock to prevent | ||
| 13496 | concurrent table modifications here. | ||
| 13497 | */ | ||
| 13498 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 109 times.
|
109 | assert(table->mdl_ticket->get_type() == MDL_EXCLUSIVE); |
| 13499 | 109 | bool empty_table = false; | |
| 13500 |
2/4✓ Branch 0 taken 109 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 109 times.
|
113 | if (table_is_empty(table_list->table, &empty_table)) goto cleanup; |
| 13501 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 97 times.
|
109 | if (!empty_table) { |
| 13502 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 10 times.
|
12 | if (alter_ctx->error_if_not_empty & |
| 13503 | Alter_table_ctx::GEOMETRY_WITHOUT_DEFAULT) { | ||
| 13504 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | my_error(ER_INVALID_USE_OF_NULL, MYF(0)); |
| 13505 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | } else if ((alter_ctx->error_if_not_empty & |
| 13506 | 10 | Alter_table_ctx::DATETIME_WITHOUT_DEFAULT) && | |
| 13507 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 7 times.
|
10 | (thd->variables.sql_mode & MODE_NO_ZERO_DATE)) { |
| 13508 | /* | ||
| 13509 | Report a warning if the NO ZERO DATE MODE is enabled. The | ||
| 13510 | warning will be promoted to an error if strict mode is | ||
| 13511 | also enabled. Do not check for errors here as we check | ||
| 13512 | thd->is_error() just below. | ||
| 13513 | */ | ||
| 13514 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | (void)push_zero_date_warning(thd, alter_ctx->datetime_field); |
| 13515 | } | ||
| 13516 | |||
| 13517 |
3/4✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 8 times.
|
12 | if (thd->is_error()) goto cleanup; |
| 13518 | } | ||
| 13519 | |||
| 13520 | // Empty table, so don't allow inserts during inplace operation. | ||
| 13521 |
3/4✓ Branch 0 taken 105 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 99 times.
✓ Branch 3 taken 6 times.
|
105 | if (inplace_supported == HA_ALTER_INPLACE_NO_LOCK || |
| 13522 | inplace_supported == HA_ALTER_INPLACE_NO_LOCK_AFTER_PREPARE) | ||
| 13523 | 99 | inplace_supported = HA_ALTER_INPLACE_SHARED_LOCK; | |
| 13524 | } | ||
| 13525 | |||
| 13526 |
3/4✓ Branch 0 taken 55914 times.
✓ Branch 1 taken 1810 times.
✓ Branch 2 taken 55914 times.
✗ Branch 3 not taken.
|
57724 | DEBUG_SYNC(thd, "alter_table_inplace_after_lock_upgrade"); |
| 13527 |
1/2✓ Branch 0 taken 57724 times.
✗ Branch 1 not taken.
|
57724 | THD_STAGE_INFO(thd, stage_alter_inplace_prepare); |
| 13528 | |||
| 13529 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 45009 times.
✓ Branch 2 taken 12715 times.
✗ Branch 3 not taken.
|
57724 | switch (inplace_supported) { |
| 13530 | ✗ | case HA_ALTER_ERROR: | |
| 13531 | case HA_ALTER_INPLACE_NOT_SUPPORTED: | ||
| 13532 | ✗ | assert(0); | |
| 13533 | [[fallthrough]]; | ||
| 13534 | 45009 | case HA_ALTER_INPLACE_NO_LOCK: | |
| 13535 | case HA_ALTER_INPLACE_NO_LOCK_AFTER_PREPARE: | ||
| 13536 |
2/3✓ Branch 0 taken 44996 times.
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
|
45009 | switch (alter_info->requested_lock) { |
| 13537 | 44996 | case Alter_info::ALTER_TABLE_LOCK_DEFAULT: | |
| 13538 | case Alter_info::ALTER_TABLE_LOCK_NONE: | ||
| 13539 | 44996 | ha_alter_info->online = true; | |
| 13540 | 44996 | break; | |
| 13541 | 13 | case Alter_info::ALTER_TABLE_LOCK_SHARED: | |
| 13542 | case Alter_info::ALTER_TABLE_LOCK_EXCLUSIVE: | ||
| 13543 | 13 | break; | |
| 13544 | } | ||
| 13545 | 45009 | break; | |
| 13546 | 12715 | case HA_ALTER_INPLACE_EXCLUSIVE_LOCK: | |
| 13547 | case HA_ALTER_INPLACE_SHARED_LOCK_AFTER_PREPARE: | ||
| 13548 | case HA_ALTER_INPLACE_SHARED_LOCK: | ||
| 13549 | case HA_ALTER_INPLACE_INSTANT: | ||
| 13550 | 12715 | break; | |
| 13551 | } | ||
| 13552 | |||
| 13553 | { | ||
| 13554 | /* | ||
| 13555 | We want warnings/errors about data truncation emitted when | ||
| 13556 | values of virtual columns are evaluated in INPLACE algorithm. | ||
| 13557 | */ | ||
| 13558 | 57724 | thd->check_for_truncated_fields = CHECK_FIELD_WARN; | |
| 13559 | 57724 | thd->num_truncated_fields = 0L; | |
| 13560 | |||
| 13561 |
3/4✓ Branch 0 taken 57511 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 278 times.
✓ Branch 3 taken 57233 times.
|
57724 | if (table->file->ha_prepare_inplace_alter_table( |
| 13562 | altered_table, ha_alter_info, table_def, altered_table_def)) { | ||
| 13563 | 278 | goto rollback; | |
| 13564 | } | ||
| 13565 | |||
| 13566 | /* | ||
| 13567 | Downgrade the lock if storage engine has told us that exclusive lock was | ||
| 13568 | necessary only for prepare phase (unless we are not under LOCK TABLES) and | ||
| 13569 | user has not explicitly requested exclusive lock. | ||
| 13570 | */ | ||
| 13571 |
4/4✓ Branch 0 taken 55404 times.
✓ Branch 1 taken 1829 times.
✓ Branch 2 taken 44617 times.
✓ Branch 3 taken 10787 times.
|
57233 | if ((inplace_supported == HA_ALTER_INPLACE_SHARED_LOCK_AFTER_PREPARE || |
| 13572 | 46446 | inplace_supported == HA_ALTER_INPLACE_NO_LOCK_AFTER_PREPARE) && | |
| 13573 |
2/2✓ Branch 0 taken 46377 times.
✓ Branch 1 taken 69 times.
|
46446 | !(thd->locked_tables_mode == LTM_LOCK_TABLES || |
| 13574 |
1/2✓ Branch 0 taken 46377 times.
✗ Branch 1 not taken.
|
46377 | thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES) && |
| 13575 |
2/2✓ Branch 0 taken 46367 times.
✓ Branch 1 taken 10 times.
|
46377 | (alter_info->requested_lock != |
| 13576 | Alter_info::ALTER_TABLE_LOCK_EXCLUSIVE)) { | ||
| 13577 | /* If storage engine or user requested shared lock downgrade to SNW. */ | ||
| 13578 |
2/2✓ Branch 0 taken 44546 times.
✓ Branch 1 taken 1821 times.
|
46367 | if (inplace_supported == HA_ALTER_INPLACE_SHARED_LOCK_AFTER_PREPARE || |
| 13579 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 44539 times.
|
44546 | alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_SHARED) |
| 13580 |
1/2✓ Branch 0 taken 1828 times.
✗ Branch 1 not taken.
|
1828 | table->mdl_ticket->downgrade_lock(MDL_SHARED_NO_WRITE); |
| 13581 | else { | ||
| 13582 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 44539 times.
|
44539 | assert(inplace_supported == HA_ALTER_INPLACE_NO_LOCK_AFTER_PREPARE); |
| 13583 |
1/2✓ Branch 0 taken 44539 times.
✗ Branch 1 not taken.
|
44539 | table->mdl_ticket->downgrade_lock(MDL_SHARED_UPGRADABLE); |
| 13584 | } | ||
| 13585 | } | ||
| 13586 | |||
| 13587 |
3/4✓ Branch 0 taken 55423 times.
✓ Branch 1 taken 1810 times.
✓ Branch 2 taken 55422 times.
✗ Branch 3 not taken.
|
57233 | DEBUG_SYNC(thd, "alter_table_inplace_after_lock_downgrade"); |
| 13588 |
1/2✓ Branch 0 taken 57232 times.
✗ Branch 1 not taken.
|
57232 | THD_STAGE_INFO(thd, stage_alter_inplace); |
| 13589 | |||
| 13590 |
3/4✓ Branch 0 taken 57229 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 163 times.
✓ Branch 3 taken 57066 times.
|
57232 | if (table->file->ha_inplace_alter_table(altered_table, ha_alter_info, |
| 13591 | table_def, altered_table_def)) { | ||
| 13592 | 163 | goto rollback; | |
| 13593 | } | ||
| 13594 | |||
| 13595 | // Upgrade to EXCLUSIVE before commit. | ||
| 13596 |
3/4✓ Branch 0 taken 57066 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 57056 times.
|
57066 | if (wait_while_table_is_used(thd, table, HA_EXTRA_PREPARE_FOR_RENAME)) |
| 13597 | 10 | goto rollback; | |
| 13598 | |||
| 13599 |
3/4✓ Branch 0 taken 57056 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 57055 times.
|
57056 | if (collect_and_lock_fk_tables_for_complex_alter_table( |
| 13600 | thd, table_list, table_def, alter_ctx, alter_info, db_type, db_type, | ||
| 13601 | fk_invalidator)) | ||
| 13602 | 1 | goto rollback; | |
| 13603 | |||
| 13604 | /* | ||
| 13605 | Check if this is an ALTER command that will cause histogram statistics to | ||
| 13606 | become invalid. If that is the case; remove the histogram statistics. | ||
| 13607 | |||
| 13608 | This will take care of scenarios when INPLACE alter is used, but not COPY. | ||
| 13609 | */ | ||
| 13610 |
3/4✓ Branch 0 taken 57055 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 57054 times.
|
57055 | if (alter_table_drop_histograms(thd, table_list, ha_alter_info->alter_info, |
| 13611 | ha_alter_info->create_info, columns, | ||
| 13612 | table_def, altered_table_def)) | ||
| 13613 | 1 | goto rollback; | |
| 13614 | |||
| 13615 | /* | ||
| 13616 | If we are killed after this point, we should ignore and continue. | ||
| 13617 | We have mostly completed the operation at this point, there should | ||
| 13618 | be no long waits left. | ||
| 13619 | */ | ||
| 13620 | |||
| 13621 |
5/8✓ Branch 0 taken 57054 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 57049 times.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
|
57054 | DBUG_EXECUTE_IF("alter_table_rollback_new_index", { |
| 13622 | table->file->ha_commit_inplace_alter_table( | ||
| 13623 | altered_table, ha_alter_info, false, table_def, altered_table_def); | ||
| 13624 | my_error(ER_UNKNOWN_ERROR, MYF(0)); | ||
| 13625 | thd->check_for_truncated_fields = CHECK_FIELD_IGNORE; | ||
| 13626 | goto cleanup; | ||
| 13627 | }); | ||
| 13628 | |||
| 13629 |
3/4✓ Branch 0 taken 55239 times.
✓ Branch 1 taken 1810 times.
✓ Branch 2 taken 55239 times.
✗ Branch 3 not taken.
|
57049 | DEBUG_SYNC(thd, "alter_table_inplace_before_commit"); |
| 13630 |
1/2✓ Branch 0 taken 57049 times.
✗ Branch 1 not taken.
|
57049 | THD_STAGE_INFO(thd, stage_alter_inplace_commit); |
| 13631 | |||
| 13632 |
3/4✓ Branch 0 taken 56897 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 59 times.
✓ Branch 3 taken 56838 times.
|
57049 | if (table->file->ha_commit_inplace_alter_table( |
| 13633 | altered_table, ha_alter_info, true, table_def, altered_table_def)) { | ||
| 13634 | 59 | goto rollback; | |
| 13635 | } | ||
| 13636 | |||
| 13637 | 56838 | thd->check_for_truncated_fields = CHECK_FIELD_IGNORE; | |
| 13638 | |||
| 13639 |
1/2✓ Branch 0 taken 56838 times.
✗ Branch 1 not taken.
|
56838 | close_all_tables_for_name(thd, table->s, false, nullptr); |
| 13640 | 56838 | table_list->table = table = nullptr; | |
| 13641 | 56838 | reopen_tables = true; | |
| 13642 |
1/2✓ Branch 0 taken 56838 times.
✗ Branch 1 not taken.
|
56838 | close_temporary_table(thd, altered_table, true, false); |
| 13643 | 56838 | rollback_needs_dict_cache_reset = true; | |
| 13644 | |||
| 13645 | /* | ||
| 13646 | Replace table definition in the data-dictionary. | ||
| 13647 | |||
| 13648 | Note that any error after this point is really awkward for storage engines | ||
| 13649 | which don't support atomic DDL. Changes to table in SE are already | ||
| 13650 | committed and can't be rolled back. Failure to update data-dictionary or | ||
| 13651 | binary log will create inconsistency between them and SE. Since we can't | ||
| 13652 | do much in this situation we simply return error and hope that old table | ||
| 13653 | definition is compatible enough with a new one. | ||
| 13654 | |||
| 13655 | For engines supporting atomic DDL error is business-as-usual situation. | ||
| 13656 | Rollback of statement which happens on error should revert changes to | ||
| 13657 | table in SE as well. | ||
| 13658 | */ | ||
| 13659 |
2/4✓ Branch 0 taken 56838 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 56838 times.
✗ Branch 3 not taken.
|
56838 | altered_table_def->set_schema_id(table_def->schema_id()); |
| 13660 |
2/4✓ Branch 0 taken 56838 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 56838 times.
✗ Branch 3 not taken.
|
56838 | altered_table_def->set_name(alter_ctx->alias); |
| 13661 |
1/2✓ Branch 0 taken 56838 times.
✗ Branch 1 not taken.
|
56838 | altered_table_def->set_hidden(dd::Abstract_table::HT_VISIBLE); |
| 13662 | |||
| 13663 | /* | ||
| 13664 | Copy pre-existing triggers to the new table definition. | ||
| 13665 | Since trigger names have to be unique per schema, we cannot | ||
| 13666 | create them while both the old and the new version of the | ||
| 13667 | table definition exist. Note that we drop the old table before | ||
| 13668 | we call update on the new table definition. | ||
| 13669 | */ | ||
| 13670 |
1/2✓ Branch 0 taken 56838 times.
✗ Branch 1 not taken.
|
56838 | altered_table_def->copy_triggers(table_def); |
| 13671 | |||
| 13672 | /* About the remove the old table definition, if there any columns | ||
| 13673 | with compression dictionary, remove the entries from | ||
| 13674 | mysql.compression_dictionary_cols table */ | ||
| 13675 |
2/4✓ Branch 0 taken 56838 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 56838 times.
|
56838 | if (compression_dict::cols_table_delete(thd, *table_def)) { |
| 13676 | ✗ | goto cleanup2; | |
| 13677 | } | ||
| 13678 | |||
| 13679 |
2/4✓ Branch 0 taken 56838 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 56838 times.
|
56838 | if (thd->dd_client()->drop(table_def)) goto cleanup2; |
| 13680 | 56838 | table_def = nullptr; | |
| 13681 | |||
| 13682 |
3/4✓ Branch 0 taken 55028 times.
✓ Branch 1 taken 1810 times.
✓ Branch 2 taken 55028 times.
✗ Branch 3 not taken.
|
56838 | DEBUG_SYNC_C("alter_table_after_dd_client_drop"); |
| 13683 | |||
| 13684 | // Reset check constraint's mode. | ||
| 13685 |
1/2✓ Branch 0 taken 56838 times.
✗ Branch 1 not taken.
|
56838 | reset_check_constraints_alter_mode(altered_table_def); |
| 13686 | |||
| 13687 |
2/2✓ Branch 0 taken 53377 times.
✓ Branch 1 taken 3461 times.
|
56838 | if ((db_type->flags & HTON_SUPPORTS_ATOMIC_DDL)) { |
| 13688 | /* | ||
| 13689 | For engines supporting atomic DDL we have delayed storing new | ||
| 13690 | table definition in the data-dictionary so far in order to avoid | ||
| 13691 | conflicts between old and new definitions on foreign key names. | ||
| 13692 | Since the old table definition is gone we can safely store new | ||
| 13693 | definition now. | ||
| 13694 | */ | ||
| 13695 |
3/4✓ Branch 0 taken 53377 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 53375 times.
|
53377 | if (thd->dd_client()->store(altered_table_def)) goto cleanup2; |
| 13696 | } else { | ||
| 13697 |
2/4✓ Branch 0 taken 3461 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3461 times.
|
3461 | if (thd->dd_client()->update(altered_table_def)) goto cleanup2; |
| 13698 | |||
| 13699 | /* | ||
| 13700 | Persist changes to data-dictionary for storage engines which don't | ||
| 13701 | support atomic DDL. Such SEs can't rollback in-place changes if error | ||
| 13702 | or crash happens after this point, so we are better to have | ||
| 13703 | data-dictionary in sync with SE. | ||
| 13704 | |||
| 13705 | Prevent intermediate commits to invoke commit order | ||
| 13706 | */ | ||
| 13707 |
1/2✓ Branch 0 taken 3461 times.
✗ Branch 1 not taken.
|
3461 | Implicit_substatement_state_guard substatement_guard(thd); |
| 13708 | |||
| 13709 |
5/10✓ Branch 0 taken 3461 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3461 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3461 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 3461 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 3461 times.
|
3461 | if (trans_commit_stmt(thd) || trans_commit_implicit(thd)) goto cleanup2; |
| 13710 |
1/2✓ Branch 0 taken 3461 times.
✗ Branch 1 not taken.
|
3461 | } |
| 13711 | } | ||
| 13712 | |||
| 13713 | #ifdef HAVE_PSI_TABLE_INTERFACE | ||
| 13714 | PSI_TABLE_CALL(drop_table_share) | ||
| 13715 | 56836 | (true, alter_ctx->new_db, static_cast<int>(strlen(alter_ctx->new_db)), | |
| 13716 |
1/2✓ Branch 0 taken 56836 times.
✗ Branch 1 not taken.
|
56836 | alter_ctx->tmp_name, static_cast<int>(strlen(alter_ctx->tmp_name))); |
| 13717 | #endif | ||
| 13718 | |||
| 13719 |
2/8✓ Branch 0 taken 56836 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 56836 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
56836 | DBUG_EXECUTE_IF("crash_after_index_create", |
| 13720 | DBUG_SET("-d,crash_after_index_create"); | ||
| 13721 | DBUG_SUICIDE();); | ||
| 13722 | |||
| 13723 | /* | ||
| 13724 | Tell the SE that the changed table in the data-dictionary. | ||
| 13725 | For engines which don't support atomic DDL this needs to be | ||
| 13726 | done before trying to rename the table. | ||
| 13727 | */ | ||
| 13728 |
2/2✓ Branch 0 taken 3461 times.
✓ Branch 1 taken 53375 times.
|
56836 | if (!(db_type->flags & HTON_SUPPORTS_ATOMIC_DDL)) { |
| 13729 |
1/2✓ Branch 0 taken 3461 times.
✗ Branch 1 not taken.
|
3461 | Open_table_context ot_ctx(thd, MYSQL_OPEN_REOPEN); |
| 13730 | |||
| 13731 | 3461 | table_list->mdl_request.ticket = mdl_ticket; | |
| 13732 |
2/4✓ Branch 0 taken 3461 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3461 times.
|
3461 | if (open_table(thd, table_list, &ot_ctx)) goto cleanup2; |
| 13733 | |||
| 13734 |
1/2✓ Branch 0 taken 3461 times.
✗ Branch 1 not taken.
|
3461 | table_list->table->file->ha_notify_table_changed(ha_alter_info); |
| 13735 | |||
| 13736 | /* | ||
| 13737 | We might be going to reopen table down on the road, so we have to | ||
| 13738 | restore state of the TABLE object which we used for obtaining of | ||
| 13739 | handler object to make it usable for later reopening. | ||
| 13740 | */ | ||
| 13741 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3461 times.
|
3461 | assert(table_list->table == thd->open_tables); |
| 13742 |
1/2✓ Branch 0 taken 3461 times.
✗ Branch 1 not taken.
|
3461 | close_thread_table(thd, &thd->open_tables); |
| 13743 | 3461 | table_list->table = nullptr; | |
| 13744 | |||
| 13745 | /* | ||
| 13746 | Remove TABLE and TABLE_SHARE for from the TDC as we might have to | ||
| 13747 | rename table later. | ||
| 13748 | */ | ||
| 13749 |
1/2✓ Branch 0 taken 3461 times.
✗ Branch 1 not taken.
|
3461 | tdc_remove_table(thd, TDC_RT_REMOVE_ALL, alter_ctx->db, |
| 13750 | alter_ctx->table_name, false); | ||
| 13751 | } | ||
| 13752 | |||
| 13753 | // Rename altered table if requested. | ||
| 13754 |
2/2✓ Branch 0 taken 160 times.
✓ Branch 1 taken 56676 times.
|
56836 | if (alter_ctx->is_table_renamed()) { |
| 13755 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 160 times.
|
160 | if (mysql_rename_table( |
| 13756 | thd, db_type, alter_ctx->db, alter_ctx->table_name, alter_ctx->db, | ||
| 13757 | alter_ctx->table_name, new_schema, alter_ctx->new_db, | ||
| 13758 | alter_ctx->new_alias, | ||
| 13759 |
1/2✓ Branch 0 taken 160 times.
✗ Branch 1 not taken.
|
160 | ((db_type->flags & HTON_SUPPORTS_ATOMIC_DDL) ? NO_DD_COMMIT : 0))) { |
| 13760 | /* | ||
| 13761 | If the rename fails we will still have a working table | ||
| 13762 | with the old name, but with other changes applied. | ||
| 13763 | */ | ||
| 13764 | ✗ | goto cleanup2; | |
| 13765 | } | ||
| 13766 | } | ||
| 13767 | |||
| 13768 | /* | ||
| 13769 | We don't have SEs which support FKs and don't support atomic DDL. | ||
| 13770 | If we ever to support such engines we need to decide how to handle | ||
| 13771 | errors in the below code for them. | ||
| 13772 | */ | ||
| 13773 |
3/4✓ Branch 0 taken 53375 times.
✓ Branch 1 taken 3461 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 53375 times.
|
56836 | assert(!(db_type->flags & HTON_SUPPORTS_FOREIGN_KEYS) || |
| 13774 | (db_type->flags & HTON_SUPPORTS_ATOMIC_DDL)); | ||
| 13775 | |||
| 13776 |
2/4✓ Branch 0 taken 56836 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 56836 times.
|
56836 | if (adjust_fks_for_complex_alter_table(thd, table_list, alter_ctx, alter_info, |
| 13777 | db_type, fk_invalidator)) | ||
| 13778 | ✗ | goto cleanup2; | |
| 13779 | |||
| 13780 |
1/2✓ Branch 0 taken 56836 times.
✗ Branch 1 not taken.
|
56836 | THD_STAGE_INFO(thd, stage_end); |
| 13781 | |||
| 13782 |
2/6✓ Branch 0 taken 56836 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 56836 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
56836 | DBUG_EXECUTE_IF("sleep_alter_before_main_binlog", my_sleep(6000000);); |
| 13783 |
3/4✓ Branch 0 taken 55026 times.
✓ Branch 1 taken 1810 times.
✓ Branch 2 taken 55026 times.
✗ Branch 3 not taken.
|
56836 | DEBUG_SYNC(thd, "alter_table_before_main_binlog"); |
| 13784 | |||
| 13785 | 113672 | ha_binlog_log_query(thd, ha_alter_info->create_info->db_type, | |
| 13786 |
3/6✓ Branch 0 taken 56836 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 56836 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 56836 times.
✗ Branch 5 not taken.
|
56836 | LOGCOM_ALTER_TABLE, thd->query().str, thd->query().length, |
| 13787 | alter_ctx->db, alter_ctx->table_name); | ||
| 13788 | |||
| 13789 |
5/6✓ Branch 0 taken 26882 times.
✓ Branch 1 taken 29954 times.
✓ Branch 2 taken 25111 times.
✓ Branch 3 taken 1771 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 25111 times.
|
56836 | assert(!(mysql_bin_log.is_open() && |
| 13790 | thd->is_current_stmt_binlog_format_row() && | ||
| 13791 | (ha_alter_info->create_info->options & HA_LEX_CREATE_TMP_TABLE))); | ||
| 13792 | |||
| 13793 |
4/6✓ Branch 0 taken 56836 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 56836 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 56832 times.
|
56836 | if (write_bin_log(thd, true, thd->query().str, thd->query().length, |
| 13794 |
1/2✓ Branch 0 taken 56836 times.
✗ Branch 1 not taken.
|
56836 | (db_type->flags & HTON_SUPPORTS_ATOMIC_DDL))) |
| 13795 | 4 | goto cleanup2; | |
| 13796 | |||
| 13797 | { | ||
| 13798 |
1/2✓ Branch 0 taken 56832 times.
✗ Branch 1 not taken.
|
56832 | Uncommitted_tables_guard uncommitted_tables(thd); |
| 13799 | |||
| 13800 |
1/2✓ Branch 0 taken 56832 times.
✗ Branch 1 not taken.
|
56832 | uncommitted_tables.add_table(table_list); |
| 13801 | |||
| 13802 | bool views_err = | ||
| 13803 | 56832 | (alter_ctx->is_table_renamed() | |
| 13804 |
2/2✓ Branch 0 taken 158 times.
✓ Branch 1 taken 56674 times.
|
56990 | ? update_referencing_views_metadata( |
| 13805 | thd, table_list, alter_ctx->new_db, alter_ctx->new_name, | ||
| 13806 |
1/2✓ Branch 0 taken 158 times.
✗ Branch 1 not taken.
|
158 | !(db_type->flags & HTON_SUPPORTS_ATOMIC_DDL), |
| 13807 | &uncommitted_tables) | ||
| 13808 | 56674 | : update_referencing_views_metadata( | |
| 13809 | thd, table_list, | ||
| 13810 |
1/2✓ Branch 0 taken 56674 times.
✗ Branch 1 not taken.
|
56674 | !(db_type->flags & HTON_SUPPORTS_ATOMIC_DDL), |
| 13811 | 56832 | &uncommitted_tables)); | |
| 13812 | |||
| 13813 |
2/2✓ Branch 0 taken 158 times.
✓ Branch 1 taken 56674 times.
|
56832 | if (alter_ctx->is_table_renamed()) |
| 13814 |
1/2✓ Branch 0 taken 158 times.
✗ Branch 1 not taken.
|
158 | tdc_remove_table(thd, TDC_RT_REMOVE_ALL, alter_ctx->new_db, |
| 13815 | alter_ctx->new_name, false); | ||
| 13816 | |||
| 13817 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 56831 times.
|
56832 | if (views_err) goto cleanup2; |
| 13818 |
2/2✓ Branch 0 taken 56831 times.
✓ Branch 1 taken 1 times.
|
56832 | } |
| 13819 | |||
| 13820 |
3/4✓ Branch 0 taken 55021 times.
✓ Branch 1 taken 1810 times.
✓ Branch 2 taken 55021 times.
✗ Branch 3 not taken.
|
56831 | DEBUG_SYNC(thd, "action_after_write_bin_log"); |
| 13821 | |||
| 13822 |
2/2✓ Branch 0 taken 53371 times.
✓ Branch 1 taken 3460 times.
|
56831 | if (db_type->flags & HTON_SUPPORTS_ATOMIC_DDL) { |
| 13823 | 53371 | enum_implicit_substatement_guard_mode mode = | |
| 13824 | enum_implicit_substatement_guard_mode :: | ||
| 13825 | ENABLE_GTID_AND_SPCO_IF_SPCO_ACTIVE; | ||
| 13826 | |||
| 13827 | /* Disable GTID and SPCO for OPTIMIZE TABLE to avoid deadlock. */ | ||
| 13828 |
2/2✓ Branch 0 taken 2065 times.
✓ Branch 1 taken 51306 times.
|
53371 | if (thd->lex->sql_command == SQLCOM_OPTIMIZE) |
| 13829 | 2065 | mode = enum_implicit_substatement_guard_mode :: | |
| 13830 | DISABLE_GTID_AND_SPCO_IF_SPCO_ACTIVE; | ||
| 13831 | |||
| 13832 | /* | ||
| 13833 | It allows saving GTID and invoking commit order, except when | ||
| 13834 | replica-preserve-commit-order is enabled and OPTIMIZE TABLE command | ||
| 13835 | is getting executed. The exception for OPTIMIZE TABLE command is | ||
| 13836 | because if it does enter commit order here and at the same time | ||
| 13837 | any operation on the table which is getting optimized is done, | ||
| 13838 | it results in deadlock. | ||
| 13839 | */ | ||
| 13840 |
1/2✓ Branch 0 taken 53371 times.
✗ Branch 1 not taken.
|
53371 | Implicit_substatement_state_guard guard(thd, mode); |
| 13841 | |||
| 13842 | /* | ||
| 13843 | Commit ALTER TABLE. Needs to be done here and not in the callers | ||
| 13844 | (which do it anyway) to be able notify SE about changed table. | ||
| 13845 | */ | ||
| 13846 |
5/10✓ Branch 0 taken 53371 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 53371 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 53338 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 53338 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 53338 times.
|
53371 | if (trans_commit_stmt(thd) || trans_commit_implicit(thd)) goto cleanup2; |
| 13847 | |||
| 13848 | /* Call SE DDL post-commit hook. */ | ||
| 13849 |
2/4✓ Branch 0 taken 53338 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 53253 times.
✗ Branch 3 not taken.
|
53338 | if (db_type->post_ddl) db_type->post_ddl(thd); |
| 13850 | |||
| 13851 | /* | ||
| 13852 | Finally we can tell SE supporting atomic DDL that the changed table | ||
| 13853 | in the data-dictionary. | ||
| 13854 | */ | ||
| 13855 | TABLE_LIST new_table_list(alter_ctx->new_db, alter_ctx->new_name, | ||
| 13856 |
1/2✓ Branch 0 taken 53253 times.
✗ Branch 1 not taken.
|
53253 | alter_ctx->new_alias, TL_READ); |
| 13857 | 53253 | new_table_list.mdl_request.ticket = | |
| 13858 |
2/2✓ Branch 0 taken 158 times.
✓ Branch 1 taken 53095 times.
|
53253 | alter_ctx->is_table_renamed() ? alter_ctx->target_mdl_request.ticket |
| 13859 | : mdl_ticket; | ||
| 13860 | |||
| 13861 |
1/2✓ Branch 0 taken 53253 times.
✗ Branch 1 not taken.
|
53253 | Open_table_context ot_ctx(thd, MYSQL_OPEN_REOPEN); |
| 13862 | |||
| 13863 |
3/4✓ Branch 0 taken 53253 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 53252 times.
|
53253 | if (open_table(thd, &new_table_list, &ot_ctx)) return true; |
| 13864 | |||
| 13865 |
1/2✓ Branch 0 taken 53252 times.
✗ Branch 1 not taken.
|
53252 | new_table_list.table->file->ha_notify_table_changed(ha_alter_info); |
| 13866 | |||
| 13867 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 53252 times.
|
53252 | assert(new_table_list.table == thd->open_tables); |
| 13868 |
1/2✓ Branch 0 taken 53252 times.
✗ Branch 1 not taken.
|
53252 | close_thread_table(thd, &thd->open_tables); |
| 13869 |
2/3✓ Branch 0 taken 53252 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
53253 | } |
| 13870 | |||
| 13871 | // TODO: May move the opening of the table and the call to | ||
| 13872 | // ha_notify_table_changed() here to make sure we don't | ||
| 13873 | // notify the handler until all meta data is complete. | ||
| 13874 | |||
| 13875 | 56712 | return false; | |
| 13876 | |||
| 13877 | 512 | rollback: | |
| 13878 |
1/2✓ Branch 0 taken 512 times.
✗ Branch 1 not taken.
|
512 | table->file->ha_commit_inplace_alter_table( |
| 13879 | altered_table, ha_alter_info, false, table_def, altered_table_def); | ||
| 13880 | 512 | thd->check_for_truncated_fields = CHECK_FIELD_IGNORE; | |
| 13881 | |||
| 13882 | 563 | cleanup: | |
| 13883 |
1/2✓ Branch 0 taken 563 times.
✗ Branch 1 not taken.
|
563 | close_temporary_table(thd, altered_table, true, false); |
| 13884 | |||
| 13885 | 570 | cleanup2: | |
| 13886 | |||
| 13887 |
1/2✓ Branch 0 taken 570 times.
✗ Branch 1 not taken.
|
570 | (void)trans_rollback_stmt(thd); |
| 13888 | /* | ||
| 13889 | Full rollback in case we have THD::transaction_rollback_request | ||
| 13890 | and to synchronize DD state in cache and on disk (as statement | ||
| 13891 | rollback doesn't clear DD cache of modified uncommitted objects). | ||
| 13892 | */ | ||
| 13893 |
1/2✓ Branch 0 taken 570 times.
✗ Branch 1 not taken.
|
570 | (void)trans_rollback(thd); |
| 13894 | |||
| 13895 |
3/4✓ Branch 0 taken 483 times.
✓ Branch 1 taken 87 times.
✓ Branch 2 taken 483 times.
✗ Branch 3 not taken.
|
570 | if ((db_type->flags & HTON_SUPPORTS_ATOMIC_DDL) && db_type->post_ddl) |
| 13896 |
1/2✓ Branch 0 taken 483 times.
✗ Branch 1 not taken.
|
483 | db_type->post_ddl(thd); |
| 13897 | |||
| 13898 | /* | ||
| 13899 | InnoDB requires additional SE dictionary cache invalidation if we roll back | ||
| 13900 | after successful call to handler::ha_commit_inplace_alter_table(). | ||
| 13901 | */ | ||
| 13902 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 563 times.
|
570 | if (rollback_needs_dict_cache_reset) { |
| 13903 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1 times.
|
7 | if (db_type->dict_cache_reset != nullptr) |
| 13904 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | db_type->dict_cache_reset(alter_ctx->db, alter_ctx->table_name); |
| 13905 | } | ||
| 13906 | |||
| 13907 | /* | ||
| 13908 | Re-opening of table needs to be done after rolling back the failed | ||
| 13909 | statement/transaction and clearing THD::transaction_rollback_request | ||
| 13910 | flag. | ||
| 13911 | */ | ||
| 13912 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 538 times.
|
570 | if (reopen_tables) { |
| 13913 | /* Close the only table instance which might be still around. */ | ||
| 13914 |
3/4✓ Branch 0 taken 25 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 25 times.
✗ Branch 3 not taken.
|
32 | if (table) close_all_tables_for_name(thd, table->s, false, nullptr); |
| 13915 | |||
| 13916 | /* | ||
| 13917 | For engines which support atomic DDL all changes were reverted | ||
| 13918 | by this point, so we can safely reopen them using old name. | ||
| 13919 | |||
| 13920 | For engines which do not support atomic DDL we can't be sure | ||
| 13921 | that rename step was reverted, so we simply remove table from | ||
| 13922 | the list of locked tables. We also downgrade/release metadata | ||
| 13923 | locks later. This won't mess up FK-related invariants for LOCK | ||
| 13924 | TABLES as such engines do not support FKs. | ||
| 13925 | */ | ||
| 13926 |
6/6✓ Branch 0 taken 25 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 24 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 31 times.
|
57 | if (!(db_type->flags & HTON_SUPPORTS_ATOMIC_DDL) && |
| 13927 | 25 | alter_ctx->is_table_renamed()) { | |
| 13928 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | assert(!(db_type->flags & HTON_SUPPORTS_FOREIGN_KEYS)); |
| 13929 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | thd->locked_tables_list.unlink_all_closed_tables(thd, nullptr, 0); |
| 13930 | } | ||
| 13931 | |||
| 13932 |
1/2✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
|
32 | (void)thd->locked_tables_list.reopen_tables(thd); |
| 13933 | } | ||
| 13934 | |||
| 13935 |
2/2✓ Branch 0 taken 87 times.
✓ Branch 1 taken 483 times.
|
570 | if (!(db_type->flags & HTON_SUPPORTS_ATOMIC_DDL)) { |
| 13936 | 87 | const dd::Table *drop_table_def = nullptr; | |
| 13937 |
4/10✓ Branch 0 taken 87 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 87 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 86 times.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
174 | if (!thd->dd_client()->acquire(alter_ctx->new_db, alter_ctx->tmp_name, |
| 13938 |
4/8✓ Branch 0 taken 87 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 87 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 87 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 87 times.
✗ Branch 7 not taken.
|
261 | &drop_table_def) && |
| 13939 |
2/2✓ Branch 0 taken 86 times.
✓ Branch 1 taken 1 times.
|
87 | (drop_table_def != nullptr)) { |
| 13940 |
1/2✓ Branch 0 taken 86 times.
✗ Branch 1 not taken.
|
86 | bool result = dd::drop_table(thd, alter_ctx->new_db, alter_ctx->tmp_name, |
| 13941 | *drop_table_def); | ||
| 13942 |
1/2✓ Branch 0 taken 86 times.
✗ Branch 1 not taken.
|
86 | (void)trans_intermediate_ddl_commit(thd, result); |
| 13943 | } | ||
| 13944 | } | ||
| 13945 | |||
| 13946 |
2/2✓ Branch 0 taken 543 times.
✓ Branch 1 taken 27 times.
|
570 | if (thd->locked_tables_mode == LTM_LOCK_TABLES || |
| 13947 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 543 times.
|
543 | thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES) |
| 13948 |
1/2✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
|
27 | mdl_ticket->downgrade_lock(MDL_SHARED_NO_READ_WRITE); |
| 13949 | |||
| 13950 | 570 | return true; | |
| 13951 | 57283 | } | |
| 13952 | |||
| 13953 | /** | ||
| 13954 | maximum possible length for certain blob types. | ||
| 13955 | |||
| 13956 | @param[in] type Blob type (e.g. MYSQL_TYPE_TINY_BLOB) | ||
| 13957 | |||
| 13958 | @return | ||
| 13959 | length | ||
| 13960 | */ | ||
| 13961 | |||
| 13962 | 15038 | static uint blob_length_by_type(enum_field_types type) { | |
| 13963 |
4/5✓ Branch 0 taken 2575 times.
✓ Branch 1 taken 11928 times.
✓ Branch 2 taken 200 times.
✓ Branch 3 taken 335 times.
✗ Branch 4 not taken.
|
15038 | switch (type) { |
| 13964 | 2575 | case MYSQL_TYPE_TINY_BLOB: | |
| 13965 | 2575 | return 255; | |
| 13966 | 11928 | case MYSQL_TYPE_BLOB: | |
| 13967 | 11928 | return 65535; | |
| 13968 | 200 | case MYSQL_TYPE_MEDIUM_BLOB: | |
| 13969 | 200 | return 16777215; | |
| 13970 | 335 | case MYSQL_TYPE_LONG_BLOB: | |
| 13971 | 335 | return 4294967295U; | |
| 13972 | ✗ | default: | |
| 13973 | ✗ | assert(0); // we should never go here | |
| 13974 | return 0; | ||
| 13975 | } | ||
| 13976 | } | ||
| 13977 | |||
| 13978 | /** | ||
| 13979 | Convert the old temporal data types to the new temporal | ||
| 13980 | type format for ADD/CHANGE COLUMN, ADD INDEXES and ALTER | ||
| 13981 | FORCE ALTER operation. | ||
| 13982 | |||
| 13983 | @param thd Thread context. | ||
| 13984 | @param alter_info Alter info parameters. | ||
| 13985 | |||
| 13986 | @retval true Error. | ||
| 13987 | @retval false Either the old temporal data types | ||
| 13988 | are not present or they are present | ||
| 13989 | and have been successfully upgraded. | ||
| 13990 | */ | ||
| 13991 | |||
| 13992 | 88227 | static bool upgrade_old_temporal_types(THD *thd, Alter_info *alter_info) { | |
| 13993 | 88227 | bool old_temporal_type_present = false; | |
| 13994 | |||
| 13995 |
1/2✓ Branch 0 taken 88227 times.
✗ Branch 1 not taken.
|
88227 | DBUG_TRACE; |
| 13996 | |||
| 13997 |
2/2✓ Branch 0 taken 69318 times.
✓ Branch 1 taken 18909 times.
|
88227 | if (!((alter_info->flags & Alter_info::ALTER_ADD_COLUMN) || |
| 13998 |
2/2✓ Branch 0 taken 54665 times.
✓ Branch 1 taken 14653 times.
|
69318 | (alter_info->flags & Alter_info::ALTER_ADD_INDEX) || |
| 13999 |
2/2✓ Branch 0 taken 37547 times.
✓ Branch 1 taken 17118 times.
|
54665 | (alter_info->flags & Alter_info::ALTER_CHANGE_COLUMN) || |
| 14000 |
2/2✓ Branch 0 taken 37453 times.
✓ Branch 1 taken 94 times.
|
37547 | (alter_info->flags & Alter_info::ALTER_RECREATE))) |
| 14001 | 37453 | return false; | |
| 14002 | |||
| 14003 | /* | ||
| 14004 | Upgrade the old temporal types if any, for ADD/CHANGE COLUMN/ | ||
| 14005 | ADD INDEXES and FORCE ALTER operation. | ||
| 14006 | */ | ||
| 14007 | Create_field *def; | ||
| 14008 |
1/2✓ Branch 0 taken 50774 times.
✗ Branch 1 not taken.
|
50774 | List_iterator<Create_field> create_it(alter_info->create_list); |
| 14009 | |||
| 14010 |
2/2✓ Branch 0 taken 748321 times.
✓ Branch 1 taken 50774 times.
|
799095 | while ((def = create_it++)) { |
| 14011 | // Check if any old temporal type is present. | ||
| 14012 |
1/2✓ Branch 0 taken 748321 times.
✗ Branch 1 not taken.
|
748321 | if ((def->sql_type == MYSQL_TYPE_TIME) || |
| 14013 |
1/2✓ Branch 0 taken 748321 times.
✗ Branch 1 not taken.
|
748321 | (def->sql_type == MYSQL_TYPE_DATETIME) || |
| 14014 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 748321 times.
|
748321 | (def->sql_type == MYSQL_TYPE_TIMESTAMP)) { |
| 14015 | ✗ | old_temporal_type_present = true; | |
| 14016 | ✗ | break; | |
| 14017 | } | ||
| 14018 | } | ||
| 14019 | |||
| 14020 | // Upgrade is not required since there are no old temporal types. | ||
| 14021 |
1/2✓ Branch 0 taken 50774 times.
✗ Branch 1 not taken.
|
50774 | if (!old_temporal_type_present) return false; |
| 14022 | |||
| 14023 | // Upgrade old temporal types to the new temporal types. | ||
| 14024 | ✗ | create_it.rewind(); | |
| 14025 | ✗ | while ((def = create_it++)) { | |
| 14026 | enum enum_field_types sql_type; | ||
| 14027 | ✗ | Item *default_value = def->constant_default; | |
| 14028 | ✗ | Item *update_value = nullptr; | |
| 14029 | |||
| 14030 | /* | ||
| 14031 | Set CURRENT_TIMESTAMP as default/update value based on | ||
| 14032 | the auto_flags value. | ||
| 14033 | */ | ||
| 14034 | |||
| 14035 | ✗ | if ((def->sql_type == MYSQL_TYPE_DATETIME || | |
| 14036 | ✗ | def->sql_type == MYSQL_TYPE_TIMESTAMP) && | |
| 14037 | ✗ | (def->auto_flags != Field::NONE)) { | |
| 14038 | ✗ | Item_func_now_local *now = new (thd->mem_root) Item_func_now_local(0); | |
| 14039 | ✗ | if (!now) return true; | |
| 14040 | |||
| 14041 | ✗ | if (def->auto_flags & Field::DEFAULT_NOW) default_value = now; | |
| 14042 | ✗ | if (def->auto_flags & Field::ON_UPDATE_NOW) update_value = now; | |
| 14043 | } | ||
| 14044 | |||
| 14045 | ✗ | switch (def->sql_type) { | |
| 14046 | ✗ | case MYSQL_TYPE_TIME: | |
| 14047 | ✗ | sql_type = MYSQL_TYPE_TIME2; | |
| 14048 | ✗ | break; | |
| 14049 | ✗ | case MYSQL_TYPE_DATETIME: | |
| 14050 | ✗ | sql_type = MYSQL_TYPE_DATETIME2; | |
| 14051 | ✗ | break; | |
| 14052 | ✗ | case MYSQL_TYPE_TIMESTAMP: | |
| 14053 | ✗ | sql_type = MYSQL_TYPE_TIMESTAMP2; | |
| 14054 | ✗ | break; | |
| 14055 | ✗ | default: | |
| 14056 | ✗ | continue; | |
| 14057 | } | ||
| 14058 | |||
| 14059 | // Replace the old temporal field with the new temporal field. | ||
| 14060 | ✗ | Create_field *temporal_field = nullptr; | |
| 14061 | ✗ | if (!(temporal_field = new (thd->mem_root) Create_field()) || | |
| 14062 | ✗ | temporal_field->init(thd, def->field_name, sql_type, nullptr, nullptr, | |
| 14063 | ✗ | (def->flags & NOT_NULL_FLAG), default_value, | |
| 14064 | ✗ | update_value, &def->comment, def->change, nullptr, | |
| 14065 | ✗ | nullptr, false, 0, &def->zip_dict_name, nullptr, | |
| 14066 | ✗ | nullptr, def->m_srid, def->hidden, def->is_array)) | |
| 14067 | ✗ | return true; | |
| 14068 | |||
| 14069 | ✗ | temporal_field->field = def->field; | |
| 14070 | ✗ | create_it.replace(temporal_field); | |
| 14071 | } | ||
| 14072 | |||
| 14073 | // Report a NOTE informing about the upgrade. | ||
| 14074 | ✗ | push_warning(thd, Sql_condition::SL_NOTE, ER_OLD_TEMPORALS_UPGRADED, | |
| 14075 | ER_THD(thd, ER_OLD_TEMPORALS_UPGRADED)); | ||
| 14076 | ✗ | return false; | |
| 14077 | 88227 | } | |
| 14078 | |||
| 14079 | 598 | static fk_option to_fk_option(dd::Foreign_key::enum_rule rule) { | |
| 14080 |
4/6✓ Branch 0 taken 433 times.
✓ Branch 1 taken 21 times.
✓ Branch 2 taken 103 times.
✓ Branch 3 taken 41 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
598 | switch (rule) { |
| 14081 | 433 | case dd::Foreign_key::enum_rule::RULE_NO_ACTION: | |
| 14082 | 433 | return FK_OPTION_NO_ACTION; | |
| 14083 | 21 | case dd::Foreign_key::enum_rule::RULE_RESTRICT: | |
| 14084 | 21 | return FK_OPTION_RESTRICT; | |
| 14085 | 103 | case dd::Foreign_key::enum_rule::RULE_CASCADE: | |
| 14086 | 103 | return FK_OPTION_CASCADE; | |
| 14087 | 41 | case dd::Foreign_key::enum_rule::RULE_SET_NULL: | |
| 14088 | 41 | return FK_OPTION_SET_NULL; | |
| 14089 | ✗ | case dd::Foreign_key::enum_rule::RULE_SET_DEFAULT: | |
| 14090 | ✗ | return FK_OPTION_DEFAULT; | |
| 14091 | } | ||
| 14092 | ✗ | assert(false); | |
| 14093 | return FK_OPTION_UNDEF; | ||
| 14094 | } | ||
| 14095 | |||
| 14096 | 299 | static fk_match_opt to_fk_match_opt(dd::Foreign_key::enum_match_option match) { | |
| 14097 |
1/4✓ Branch 0 taken 299 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
299 | switch (match) { |
| 14098 | 299 | case dd::Foreign_key::enum_match_option::OPTION_NONE: | |
| 14099 | 299 | return FK_MATCH_SIMPLE; | |
| 14100 | ✗ | case dd::Foreign_key::enum_match_option::OPTION_PARTIAL: | |
| 14101 | ✗ | return FK_MATCH_PARTIAL; | |
| 14102 | ✗ | case dd::Foreign_key::enum_match_option::OPTION_FULL: | |
| 14103 | ✗ | return FK_MATCH_FULL; | |
| 14104 | } | ||
| 14105 | ✗ | assert(false); | |
| 14106 | return FK_MATCH_UNDEF; | ||
| 14107 | } | ||
| 14108 | |||
| 14109 | 1234 | static void to_lex_cstring(MEM_ROOT *mem_root, LEX_CSTRING *target, | |
| 14110 | const dd::String_type &source) { | ||
| 14111 | 1234 | target->str = strmake_root(mem_root, source.c_str(), source.length() + 1); | |
| 14112 | 1234 | target->length = source.length(); | |
| 14113 | 1234 | } | |
| 14114 | |||
| 14115 | /** | ||
| 14116 | Remember information about pre-existing foreign keys so | ||
| 14117 | that they can be added to the new version of the table later. | ||
| 14118 | Omit foreign keys to be dropped. Also check that the foreign | ||
| 14119 | keys to be kept are still valid. | ||
| 14120 | |||
| 14121 | @note This function removes pre-existing foreign keys from the | ||
| 14122 | drop_list, while Alter_info::drop_list is kept intact. | ||
| 14123 | A non-empty drop_list upon return of this function indicates | ||
| 14124 | an error, and means that the statement tries to drop a | ||
| 14125 | foreign key that did not exist in the first place. | ||
| 14126 | |||
| 14127 | @param[in] thd Thread handle. | ||
| 14128 | @param[in] src_table The source table. | ||
| 14129 | @param[in] src_db_name Original database name of table. | ||
| 14130 | @param[in] src_table_name Original table name of table. | ||
| 14131 | @param[in] hton Original storage engine. | ||
| 14132 | @param[in] alter_info Info about ALTER TABLE statement. | ||
| 14133 | @param[in] new_create_list List of new columns, used for rename check. | ||
| 14134 | @param[in,out] drop_list Copy of list of foreign keys to be dropped. | ||
| 14135 | @param[in,out] alter_ctx Runtime context for ALTER TABLE to which | ||
| 14136 | information about pre-existing foreign | ||
| 14137 | keys is added. | ||
| 14138 | */ | ||
| 14139 | |||
| 14140 | 72969 | static bool transfer_preexisting_foreign_keys( | |
| 14141 | THD *thd, const dd::Table *src_table, const char *src_db_name, | ||
| 14142 | const char *src_table_name, handlerton *hton, const Alter_info *alter_info, | ||
| 14143 | List<Create_field> *new_create_list, Alter_table_ctx *alter_ctx, | ||
| 14144 | Prealloced_array<const Alter_drop *, 1> *drop_list) { | ||
| 14145 |
2/2✓ Branch 0 taken 4243 times.
✓ Branch 1 taken 68726 times.
|
72969 | if (src_table == nullptr) |
| 14146 | 4243 | return false; // Could be temporary table or during upgrade. | |
| 14147 | |||
| 14148 |
1/2✓ Branch 0 taken 68726 times.
✗ Branch 1 not taken.
|
68726 | List_iterator<Create_field> find_it(*new_create_list); |
| 14149 | |||
| 14150 |
1/2✓ Branch 0 taken 68726 times.
✗ Branch 1 not taken.
|
68726 | alter_ctx->fk_info = (FOREIGN_KEY *)sql_calloc( |
| 14151 |
1/2✓ Branch 0 taken 68726 times.
✗ Branch 1 not taken.
|
68726 | sizeof(FOREIGN_KEY) * src_table->foreign_keys().size()); |
| 14152 |
3/4✓ Branch 0 taken 69084 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 364 times.
✓ Branch 3 taken 68720 times.
|
69084 | for (size_t i = 0; i < src_table->foreign_keys().size(); i++) { |
| 14153 |
2/4✓ Branch 0 taken 364 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 364 times.
✗ Branch 3 not taken.
|
364 | const dd::Foreign_key *dd_fk = src_table->foreign_keys()[i]; |
| 14154 | |||
| 14155 | // Skip foreign keys that are to be dropped | ||
| 14156 | 364 | size_t k = 0; | |
| 14157 |
3/4✓ Branch 0 taken 436 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 137 times.
✓ Branch 3 taken 299 times.
|
436 | while (k < drop_list->size()) { |
| 14158 |
1/2✓ Branch 0 taken 137 times.
✗ Branch 1 not taken.
|
137 | const Alter_drop *drop = (*drop_list)[k]; |
| 14159 | // Index names are always case insensitive | ||
| 14160 |
4/4✓ Branch 0 taken 80 times.
✓ Branch 1 taken 57 times.
✓ Branch 2 taken 65 times.
✓ Branch 3 taken 72 times.
|
217 | if (drop->type == Alter_drop::FOREIGN_KEY && |
| 14161 |
4/6✓ Branch 0 taken 80 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 80 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 65 times.
✓ Branch 5 taken 15 times.
|
80 | my_strcasecmp(system_charset_info, drop->name, |
| 14162 | dd_fk->name().c_str()) == 0) { | ||
| 14163 | 65 | break; | |
| 14164 | } | ||
| 14165 | 72 | k++; | |
| 14166 | } | ||
| 14167 |
3/4✓ Branch 0 taken 364 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 65 times.
✓ Branch 3 taken 299 times.
|
364 | if (k < drop_list->size()) { |
| 14168 |
1/2✓ Branch 0 taken 65 times.
✗ Branch 1 not taken.
|
65 | drop_list->erase(k); |
| 14169 | 65 | continue; | |
| 14170 | } | ||
| 14171 | |||
| 14172 | // Self-referencing foreign keys will need additional handling later. | ||
| 14173 | bool is_self_referencing = | ||
| 14174 |
2/4✓ Branch 0 taken 299 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 299 times.
✗ Branch 3 not taken.
|
299 | my_strcasecmp(table_alias_charset, |
| 14175 | dd_fk->referenced_table_schema_name().c_str(), | ||
| 14176 |
2/2✓ Branch 0 taken 295 times.
✓ Branch 1 taken 4 times.
|
594 | src_db_name) == 0 && |
| 14177 |
4/6✓ Branch 0 taken 295 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 295 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 294 times.
|
295 | my_strcasecmp(table_alias_charset, |
| 14178 | dd_fk->referenced_table_name().c_str(), | ||
| 14179 | 299 | src_table_name) == 0; | |
| 14180 | |||
| 14181 | 299 | FOREIGN_KEY *sql_fk = &alter_ctx->fk_info[alter_ctx->fk_count++]; | |
| 14182 | |||
| 14183 |
2/4✓ Branch 0 taken 299 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 299 times.
✗ Branch 3 not taken.
|
299 | sql_fk->name = strmake_root(thd->mem_root, dd_fk->name().c_str(), |
| 14184 |
1/2✓ Branch 0 taken 299 times.
✗ Branch 1 not taken.
|
299 | dd_fk->name().length() + 1); |
| 14185 | |||
| 14186 | 299 | sql_fk->unique_index_name = | |
| 14187 |
2/4✓ Branch 0 taken 299 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 299 times.
✗ Branch 3 not taken.
|
299 | strmake_root(thd->mem_root, dd_fk->unique_constraint_name().c_str(), |
| 14188 |
1/2✓ Branch 0 taken 299 times.
✗ Branch 1 not taken.
|
299 | dd_fk->unique_constraint_name().length() + 1); |
| 14189 | |||
| 14190 |
1/2✓ Branch 0 taken 299 times.
✗ Branch 1 not taken.
|
299 | sql_fk->key_parts = dd_fk->elements().size(); |
| 14191 | |||
| 14192 |
1/2✓ Branch 0 taken 299 times.
✗ Branch 1 not taken.
|
299 | to_lex_cstring(thd->mem_root, &sql_fk->ref_db, |
| 14193 |
1/2✓ Branch 0 taken 299 times.
✗ Branch 1 not taken.
|
299 | dd_fk->referenced_table_schema_name()); |
| 14194 | |||
| 14195 |
1/2✓ Branch 0 taken 299 times.
✗ Branch 1 not taken.
|
299 | to_lex_cstring(thd->mem_root, &sql_fk->ref_table, |
| 14196 |
1/2✓ Branch 0 taken 299 times.
✗ Branch 1 not taken.
|
299 | dd_fk->referenced_table_name()); |
| 14197 | |||
| 14198 |
1/2✓ Branch 0 taken 299 times.
✗ Branch 1 not taken.
|
299 | sql_fk->delete_opt = to_fk_option(dd_fk->delete_rule()); |
| 14199 |
1/2✓ Branch 0 taken 299 times.
✗ Branch 1 not taken.
|
299 | sql_fk->update_opt = to_fk_option(dd_fk->update_rule()); |
| 14200 |
1/2✓ Branch 0 taken 299 times.
✗ Branch 1 not taken.
|
299 | sql_fk->match_opt = to_fk_match_opt(dd_fk->match_option()); |
| 14201 | |||
| 14202 | 299 | sql_fk->key_part = | |
| 14203 |
1/2✓ Branch 0 taken 299 times.
✗ Branch 1 not taken.
|
299 | (LEX_CSTRING *)sql_calloc(sizeof(LEX_CSTRING) * sql_fk->key_parts); |
| 14204 | 299 | sql_fk->fk_key_part = | |
| 14205 |
1/2✓ Branch 0 taken 299 times.
✗ Branch 1 not taken.
|
299 | (LEX_CSTRING *)sql_calloc(sizeof(LEX_CSTRING) * sql_fk->key_parts); |
| 14206 | |||
| 14207 |
2/2✓ Branch 0 taken 334 times.
✓ Branch 1 taken 293 times.
|
627 | for (size_t j = 0; j < sql_fk->key_parts; j++) { |
| 14208 |
2/4✓ Branch 0 taken 334 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 334 times.
✗ Branch 3 not taken.
|
334 | const dd::Foreign_key_element *dd_fk_ele = dd_fk->elements()[j]; |
| 14209 | |||
| 14210 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 319 times.
|
334 | if (alter_info->flags & Alter_info::ALTER_DROP_COLUMN) { |
| 14211 | /* Check if column used in the foreign key was dropped. */ | ||
| 14212 |
4/6✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 9 times.
|
15 | if (std::any_of( |
| 14213 | alter_info->drop_list.cbegin(), alter_info->drop_list.cend(), | ||
| 14214 | 30 | [dd_fk_ele](const Alter_drop *drop) { | |
| 14215 |
1/2✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
|
30 | return drop->type == Alter_drop::COLUMN && |
| 14216 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 9 times.
|
30 | !my_strcasecmp(system_charset_info, |
| 14217 | dd_fk_ele->column().name().c_str(), | ||
| 14218 | drop->name); | ||
| 14219 | })) { | ||
| 14220 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | my_error(ER_FK_COLUMN_CANNOT_DROP, MYF(0), |
| 14221 |
3/6✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
|
6 | dd_fk_ele->column().name().c_str(), dd_fk->name().c_str()); |
| 14222 | 6 | return true; | |
| 14223 | } | ||
| 14224 | |||
| 14225 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
|
9 | if (is_self_referencing) { |
| 14226 | /* | ||
| 14227 | Do the same check for referenced column if child and parent | ||
| 14228 | table are the same. | ||
| 14229 | */ | ||
| 14230 | ✗ | find_it.rewind(); | |
| 14231 | const Create_field *find; | ||
| 14232 | ✗ | while ((find = find_it++)) { | |
| 14233 | ✗ | if (find->field && | |
| 14234 | ✗ | my_strcasecmp(system_charset_info, | |
| 14235 | dd_fk_ele->referenced_column_name().c_str(), | ||
| 14236 | find->field->field_name) == 0) { | ||
| 14237 | ✗ | break; | |
| 14238 | } | ||
| 14239 | } | ||
| 14240 | ✗ | if (find == nullptr) { | |
| 14241 | ✗ | my_error(ER_FK_COLUMN_CANNOT_DROP_CHILD, MYF(0), | |
| 14242 | ✗ | dd_fk_ele->referenced_column_name().c_str(), | |
| 14243 | ✗ | dd_fk->name().c_str(), dd_fk->table().name().c_str()); | |
| 14244 | ✗ | return true; | |
| 14245 | } | ||
| 14246 | } | ||
| 14247 | } | ||
| 14248 | |||
| 14249 | // Check if the column was renamed by the same statement. | ||
| 14250 | 328 | bool col_renamed = false; | |
| 14251 | 328 | bool ref_col_renamed = false; | |
| 14252 | |||
| 14253 |
2/2✓ Branch 0 taken 85 times.
✓ Branch 1 taken 243 times.
|
328 | if (alter_info->flags & Alter_info::ALTER_CHANGE_COLUMN) { |
| 14254 | 85 | find_it.rewind(); | |
| 14255 | const Create_field *find; | ||
| 14256 |
6/6✓ Branch 0 taken 405 times.
✓ Branch 1 taken 75 times.
✓ Branch 2 taken 395 times.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 395 times.
✓ Branch 5 taken 85 times.
|
480 | while ((find = find_it++) && !col_renamed) { |
| 14257 |
9/12✓ Branch 0 taken 101 times.
✓ Branch 1 taken 294 times.
✓ Branch 2 taken 101 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 101 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 101 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 20 times.
✓ Branch 9 taken 81 times.
✓ Branch 10 taken 20 times.
✓ Branch 11 taken 375 times.
|
395 | if (find->change && my_strcasecmp(system_charset_info, |
| 14258 | dd_fk_ele->column().name().c_str(), | ||
| 14259 | find->change) == 0) { | ||
| 14260 | // Use new name | ||
| 14261 | 20 | sql_fk->key_part[j].str = find->field_name; | |
| 14262 | 20 | sql_fk->key_part[j].length = strlen(find->field_name); | |
| 14263 | 20 | col_renamed = true; | |
| 14264 | } | ||
| 14265 | } | ||
| 14266 | |||
| 14267 | /* | ||
| 14268 | If foreign key has the same table as child and parent we also | ||
| 14269 | need to update names of referenced columns if they are renamed. | ||
| 14270 | */ | ||
| 14271 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 85 times.
|
85 | if (is_self_referencing) { |
| 14272 | ✗ | find_it.rewind(); | |
| 14273 | ✗ | while ((find = find_it++) && !ref_col_renamed) { | |
| 14274 | ✗ | if (find->change && | |
| 14275 | ✗ | my_strcasecmp(system_charset_info, | |
| 14276 | dd_fk_ele->referenced_column_name().c_str(), | ||
| 14277 | find->change) == 0) { | ||
| 14278 | // Use new name | ||
| 14279 | ✗ | sql_fk->fk_key_part[j].str = find->field_name; | |
| 14280 | ✗ | sql_fk->fk_key_part[j].length = strlen(find->field_name); | |
| 14281 | ✗ | ref_col_renamed = true; | |
| 14282 | } | ||
| 14283 | } | ||
| 14284 | } | ||
| 14285 | } | ||
| 14286 |
2/2✓ Branch 0 taken 308 times.
✓ Branch 1 taken 20 times.
|
328 | if (!col_renamed) // Use old name |
| 14287 |
1/2✓ Branch 0 taken 308 times.
✗ Branch 1 not taken.
|
308 | to_lex_cstring(thd->mem_root, &sql_fk->key_part[j], |
| 14288 |
2/4✓ Branch 0 taken 308 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 308 times.
✗ Branch 3 not taken.
|
308 | dd_fk_ele->column().name()); |
| 14289 | |||
| 14290 |
1/2✓ Branch 0 taken 328 times.
✗ Branch 1 not taken.
|
328 | if (!ref_col_renamed) |
| 14291 |
1/2✓ Branch 0 taken 328 times.
✗ Branch 1 not taken.
|
328 | to_lex_cstring(thd->mem_root, &sql_fk->fk_key_part[j], |
| 14292 |
1/2✓ Branch 0 taken 328 times.
✗ Branch 1 not taken.
|
328 | dd_fk_ele->referenced_column_name()); |
| 14293 | |||
| 14294 | /* | ||
| 14295 | Orphan non-self-referencing FK become non-orphan/adopted | ||
| 14296 | self-referencing FK as a result of a table rename operation. Make sure | ||
| 14297 | referenced column exists and it is not a virtual column. Such FK needs | ||
| 14298 | additional handling later. | ||
| 14299 | */ | ||
| 14300 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 326 times.
|
327 | if (!is_self_referencing && alter_ctx->is_table_renamed() && |
| 14301 |
3/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
1 | my_strcasecmp(table_alias_charset, |
| 14302 | dd_fk->referenced_table_schema_name().c_str(), | ||
| 14303 |
3/4✓ Branch 0 taken 327 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 328 times.
|
655 | alter_ctx->new_db) == 0 && |
| 14304 |
3/6✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
|
1 | my_strcasecmp(table_alias_charset, |
| 14305 | dd_fk->referenced_table_name().c_str(), | ||
| 14306 | alter_ctx->new_name) == 0) { | ||
| 14307 | ✗ | find_it.rewind(); | |
| 14308 | const Create_field *find; | ||
| 14309 | ✗ | while ((find = find_it++)) { | |
| 14310 | ✗ | if (find->field && | |
| 14311 | ✗ | my_strcasecmp(system_charset_info, | |
| 14312 | dd_fk_ele->referenced_column_name().c_str(), | ||
| 14313 | find->field_name) == 0) | ||
| 14314 | ✗ | break; | |
| 14315 | } | ||
| 14316 | ✗ | if (find == nullptr) { | |
| 14317 | ✗ | my_error(ER_FK_NO_COLUMN_PARENT, MYF(0), sql_fk->fk_key_part[j].str, | |
| 14318 | ✗ | dd_fk->name().c_str(), | |
| 14319 | ✗ | dd_fk->referenced_table_name().c_str()); | |
| 14320 | ✗ | return true; | |
| 14321 | } | ||
| 14322 | ✗ | if (find->is_virtual_gcol()) { | |
| 14323 | ✗ | my_error(ER_FK_CANNOT_USE_VIRTUAL_COLUMN, MYF(0), | |
| 14324 | ✗ | dd_fk->name().c_str(), sql_fk->fk_key_part[j].str); | |
| 14325 | ✗ | return true; | |
| 14326 | } | ||
| 14327 | } | ||
| 14328 | |||
| 14329 | #ifndef NDEBUG | ||
| 14330 | { | ||
| 14331 | 328 | find_it.rewind(); | |
| 14332 | Create_field *find; | ||
| 14333 |
1/2✓ Branch 0 taken 784 times.
✗ Branch 1 not taken.
|
784 | while ((find = find_it++)) { |
| 14334 |
1/2✓ Branch 0 taken 784 times.
✗ Branch 1 not taken.
|
784 | if (my_strcasecmp(system_charset_info, sql_fk->key_part[j].str, |
| 14335 |
4/4✓ Branch 0 taken 328 times.
✓ Branch 1 taken 456 times.
✓ Branch 2 taken 328 times.
✓ Branch 3 taken 456 times.
|
1112 | find->field_name) == 0 && |
| 14336 |
1/2✓ Branch 0 taken 328 times.
✗ Branch 1 not taken.
|
328 | find->field != nullptr) { |
| 14337 | 328 | break; | |
| 14338 | } | ||
| 14339 | } | ||
| 14340 | /* | ||
| 14341 | Thanks to the above code handling dropped columns referencing | ||
| 14342 | column must exist. | ||
| 14343 | */ | ||
| 14344 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 328 times.
|
328 | assert(find != nullptr); |
| 14345 | /* | ||
| 14346 | Also due to facts a) that we don't allow virtual columns in | ||
| 14347 | foreign keys and b) that existing generated columns can't be | ||
| 14348 | changed to virtual, referencing column must be non-virtual. | ||
| 14349 | */ | ||
| 14350 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 328 times.
|
328 | assert(!find->is_virtual_gcol()); |
| 14351 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 327 times.
|
328 | if (is_self_referencing) { |
| 14352 | 1 | find_it.rewind(); | |
| 14353 | |||
| 14354 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | while ((find = find_it++)) { |
| 14355 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (my_strcasecmp(system_charset_info, sql_fk->fk_key_part[j].str, |
| 14356 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
2 | find->field_name) == 0 && |
| 14357 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | find->field != nullptr) { |
| 14358 | 1 | break; | |
| 14359 | } | ||
| 14360 | } | ||
| 14361 | /* | ||
| 14362 | The same applies to referenced columns if foreign key has | ||
| 14363 | same table as child and parent. | ||
| 14364 | */ | ||
| 14365 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | assert(find != nullptr); |
| 14366 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | assert(!find->is_virtual_gcol()); |
| 14367 | } | ||
| 14368 | } | ||
| 14369 | #endif | ||
| 14370 | } | ||
| 14371 | } | ||
| 14372 | |||
| 14373 | 68720 | alter_ctx->fk_max_generated_name_number = | |
| 14374 |
1/2✓ Branch 0 taken 68720 times.
✗ Branch 1 not taken.
|
68720 | get_fk_max_generated_name_number(src_table_name, src_table, hton); |
| 14375 | |||
| 14376 | 68720 | return false; | |
| 14377 | } | ||
| 14378 | |||
| 14379 | /** | ||
| 14380 | Check if the column being removed or renamed is in use by partitioning | ||
| 14381 | function for the table and that the partitioning is kept/partitioning | ||
| 14382 | function is unchanged by this ALTER TABLE, and report error if it is | ||
| 14383 | the case. | ||
| 14384 | |||
| 14385 | @param table TABLE object describing old table version. | ||
| 14386 | @param field Field object for column to be checked. | ||
| 14387 | @param alter_info Alter_info describing the ALTER TABLE. | ||
| 14388 | |||
| 14389 | @return | ||
| 14390 | true The field is used by partitioning function, error was reported. | ||
| 14391 | false Otherwise. | ||
| 14392 | |||
| 14393 | */ | ||
| 14394 | 3658 | static bool check_if_field_used_by_partitioning_func( | |
| 14395 | TABLE *table, const Field *field, const Alter_info *alter_info) { | ||
| 14396 | 3658 | partition_info *part_info = table->part_info; | |
| 14397 | |||
| 14398 | // There is no partitioning function if table is not partitioned. | ||
| 14399 |
2/2✓ Branch 0 taken 3487 times.
✓ Branch 1 taken 171 times.
|
3658 | if (!part_info) return false; |
| 14400 | |||
| 14401 | // Check if column is not used by (sub)partitioning function. | ||
| 14402 |
2/2✓ Branch 0 taken 147 times.
✓ Branch 1 taken 24 times.
|
171 | if (!bitmap_is_set(&part_info->full_part_field_set, field->field_index())) |
| 14403 | 147 | return false; | |
| 14404 | |||
| 14405 | /* | ||
| 14406 | It is OK to rename/drop column that is used by old partitioning function | ||
| 14407 | if partitioning is removed. It is also OK to do this if partitioning for | ||
| 14408 | table is changed. The latter gives users a way to update partitioning | ||
| 14409 | function after renaming/dropping columns. Data inconsistency doesn't | ||
| 14410 | occur in this case as change of partitioning causes table rebuild. | ||
| 14411 | */ | ||
| 14412 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 13 times.
|
24 | if (alter_info->flags & |
| 14413 | (Alter_info::ALTER_REMOVE_PARTITIONING | Alter_info::ALTER_PARTITION)) | ||
| 14414 | 11 | return false; | |
| 14415 | |||
| 14416 | /* | ||
| 14417 | We also allow renaming and dropping of columns used by partitioning | ||
| 14418 | function when it is defined using PARTITION BY KEY () clause (notice | ||
| 14419 | empty column list). In this case partitioning function is defined by | ||
| 14420 | the primary key. | ||
| 14421 | So partitioning function stays valid when column in the primary key is | ||
| 14422 | renamed since the primary key is automagically adjusted in this case. | ||
| 14423 | Dropping column is also acceptable, as this is handled as a change of | ||
| 14424 | primary key (deletion of old one and addition of a new one) and storage | ||
| 14425 | engines are supposed to handle this correctly (at least InnoDB does | ||
| 14426 | thanks to fix for bug#20190520). | ||
| 14427 | |||
| 14428 | Note that we avoid complex checks and simple disallow renaming/dropping | ||
| 14429 | of columns if table with PARTITION BY KEY() clause is also subpartitioned. | ||
| 14430 | Subpartitioning by KEY always uses explicit column list so it is not safe | ||
| 14431 | for renaming/dropping columns. | ||
| 14432 | */ | ||
| 14433 | 31 | if (part_info->part_type == partition_type::HASH && | |
| 14434 |
7/8✓ Branch 0 taken 5 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 4 times.
✓ Branch 7 taken 9 times.
|
17 | part_info->list_of_part_fields && part_info->part_field_list.is_empty() && |
| 14435 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | !part_info->is_sub_partitioned()) |
| 14436 | 4 | return false; | |
| 14437 | |||
| 14438 | 9 | my_error(ER_DEPENDENT_BY_PARTITION_FUNC, MYF(0), field->field_name); | |
| 14439 | 9 | return true; | |
| 14440 | } | ||
| 14441 | |||
| 14442 | /** | ||
| 14443 | Sets column default, drops default, renames or alters visibility. | ||
| 14444 | */ | ||
| 14445 | 941112 | static bool alter_column_name_default_or_visibility( | |
| 14446 | const Alter_info *alter_info, | ||
| 14447 | Prealloced_array<const Alter_column *, 1> *alter_list, Create_field *def) { | ||
| 14448 |
1/2✓ Branch 0 taken 941112 times.
✗ Branch 1 not taken.
|
941112 | DBUG_TRACE; |
| 14449 | |||
| 14450 | // Check if ALTER TABLE has requested of such a change. | ||
| 14451 | 941112 | size_t i = 0; | |
| 14452 | 941112 | const Alter_column *alter = nullptr; | |
| 14453 |
3/4✓ Branch 0 taken 941361 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 597 times.
✓ Branch 3 taken 940764 times.
|
941361 | while (i < alter_list->size()) { |
| 14454 |
1/2✓ Branch 0 taken 597 times.
✗ Branch 1 not taken.
|
597 | alter = (*alter_list)[i]; |
| 14455 |
3/4✓ Branch 0 taken 597 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 348 times.
✓ Branch 3 taken 249 times.
|
597 | if (!my_strcasecmp(system_charset_info, def->field_name, alter->name)) |
| 14456 | 348 | break; | |
| 14457 | 249 | i++; | |
| 14458 | } | ||
| 14459 | |||
| 14460 | // Nothing changed. | ||
| 14461 |
3/4✓ Branch 0 taken 941112 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 940764 times.
✓ Branch 3 taken 348 times.
|
941112 | if (i == alter_list->size()) return false; |
| 14462 | |||
| 14463 | // Setup the field. | ||
| 14464 |
5/6✓ Branch 0 taken 144 times.
✓ Branch 1 taken 84 times.
✓ Branch 2 taken 89 times.
✓ Branch 3 taken 16 times.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
|
348 | switch (alter->change_type()) { |
| 14465 | 144 | case Alter_column::Type::SET_DEFAULT: { | |
| 14466 |
3/4✓ Branch 0 taken 54 times.
✓ Branch 1 taken 90 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 54 times.
|
144 | assert(alter->def || alter->m_default_val_expr); |
| 14467 | |||
| 14468 | // Assign new default. | ||
| 14469 | 144 | def->constant_default = alter->def; | |
| 14470 | 144 | def->m_default_val_expr = alter->m_default_val_expr; | |
| 14471 | |||
| 14472 |
3/4✓ Branch 0 taken 90 times.
✓ Branch 1 taken 54 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 90 times.
|
144 | if (alter->def && def->flags & BLOB_FLAG) { |
| 14473 | ✗ | my_error(ER_BLOB_CANT_HAVE_DEFAULT, MYF(0), def->field_name); | |
| 14474 | ✗ | return true; | |
| 14475 | } | ||
| 14476 | |||
| 14477 |
4/4✓ Branch 0 taken 54 times.
✓ Branch 1 taken 90 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 120 times.
|
198 | if (alter->m_default_val_expr != nullptr && |
| 14478 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 30 times.
|
54 | pre_validate_value_generator_expr( |
| 14479 |
1/2✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
|
54 | alter->m_default_val_expr->expr_item, alter->name, |
| 14480 | VGS_DEFAULT_EXPRESSION)) | ||
| 14481 | 24 | return true; | |
| 14482 | |||
| 14483 | // Default value is not permitted for generated columns | ||
| 14484 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 118 times.
|
120 | if (def->field->is_gcol()) { |
| 14485 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | my_error(ER_WRONG_USAGE, MYF(0), "DEFAULT", "generated column"); |
| 14486 | 2 | return true; | |
| 14487 | } | ||
| 14488 | |||
| 14489 | 118 | def->flags &= ~NO_DEFAULT_VALUE_FLAG; | |
| 14490 | /* | ||
| 14491 | The defaults are explicitly altered for the TIMESTAMP/DATETIME | ||
| 14492 | field, through SET DEFAULT. Hence, set the auto_flags member | ||
| 14493 | appropriately. | ||
| 14494 | */ | ||
| 14495 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 118 times.
|
118 | if (real_type_with_now_as_default(def->sql_type)) { |
| 14496 | ✗ | assert((def->auto_flags & ~(Field::DEFAULT_NOW | Field::ON_UPDATE_NOW | | |
| 14497 | Field::GENERATED_FROM_EXPRESSION)) == 0); | ||
| 14498 | ✗ | def->auto_flags &= ~Field::DEFAULT_NOW; | |
| 14499 | } | ||
| 14500 | /* | ||
| 14501 | Columns can't have AUTO_INCREMENT and DEFAULT/ON UPDATE | ||
| 14502 | CURRENT_TIMESTAMP/ default from expression the same time. | ||
| 14503 | */ | ||
| 14504 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 110 times.
|
118 | if ((def->auto_flags & Field::NEXT_NUMBER) != 0 && |
| 14505 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | ((def->auto_flags & (Field::DEFAULT_NOW | Field::ON_UPDATE_NOW)) != |
| 14506 | 8 | 0 || | |
| 14507 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
|
8 | def->m_default_val_expr != nullptr)) { |
| 14508 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | my_error(ER_INVALID_DEFAULT, MYF(0), def->field_name); |
| 14509 | 4 | return true; | |
| 14510 | } | ||
| 14511 | 114 | } break; | |
| 14512 | |||
| 14513 | 84 | case Alter_column::Type::DROP_DEFAULT: { | |
| 14514 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 84 times.
|
84 | assert(!alter->def); |
| 14515 | |||
| 14516 | // Mark field to have no default. | ||
| 14517 | 84 | def->constant_default = nullptr; | |
| 14518 | 84 | def->m_default_val_expr = nullptr; | |
| 14519 | 84 | def->flags |= NO_DEFAULT_VALUE_FLAG; | |
| 14520 | 84 | } break; | |
| 14521 | |||
| 14522 | 89 | case Alter_column::Type::RENAME_COLUMN: { | |
| 14523 | 89 | def->change = alter->name; | |
| 14524 | 89 | def->field_name = alter->m_new_name; | |
| 14525 | |||
| 14526 | /* | ||
| 14527 | If a generated column or a default expression is dependent | ||
| 14528 | on this column, this column cannot be renamed. | ||
| 14529 | |||
| 14530 | The same applies to case when this table is partitioned and | ||
| 14531 | partitioning function is dependent on column being renamed. | ||
| 14532 | */ | ||
| 14533 | 267 | if (check_if_field_used_by_generated_column_or_default( | |
| 14534 |
5/6✓ Branch 0 taken 89 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 83 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 10 times.
✓ Branch 5 taken 79 times.
|
172 | def->field->table, def->field, alter_info) || |
| 14535 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 79 times.
|
83 | check_if_field_used_by_partitioning_func(def->field->table, |
| 14536 |
1/2✓ Branch 0 taken 83 times.
✗ Branch 1 not taken.
|
83 | def->field, alter_info)) |
| 14537 | 10 | return true; | |
| 14538 | 79 | } break; | |
| 14539 | |||
| 14540 | 16 | case Alter_column::Type::SET_COLUMN_VISIBLE: | |
| 14541 | 16 | def->hidden = dd::Column::enum_hidden_type::HT_VISIBLE; | |
| 14542 | 16 | break; | |
| 14543 | |||
| 14544 | 15 | case Alter_column::Type::SET_COLUMN_INVISIBLE: | |
| 14545 | 15 | def->hidden = dd::Column::enum_hidden_type::HT_HIDDEN_USER; | |
| 14546 | 15 | break; | |
| 14547 | |||
| 14548 | ✗ | default: | |
| 14549 | ✗ | assert(0); | |
| 14550 | my_error(ER_UNKNOWN_ERROR, MYF(0)); | ||
| 14551 | return true; | ||
| 14552 | } | ||
| 14553 | |||
| 14554 | // Remove the element from to be altered column list. | ||
| 14555 |
1/2✓ Branch 0 taken 308 times.
✗ Branch 1 not taken.
|
308 | alter_list->erase(i); |
| 14556 | |||
| 14557 | 308 | return false; | |
| 14558 | 941112 | } | |
| 14559 | |||
| 14560 | /** | ||
| 14561 | Check if the column being removed or renamed is in use by a generated | ||
| 14562 | column, default or functional index, which will be kept around/unchanged | ||
| 14563 | by this ALTER TABLE, and report error which is appropriate for the case. | ||
| 14564 | |||
| 14565 | @param table TABLE object describing old table version. | ||
| 14566 | @param field Field object for column to be checked. | ||
| 14567 | @param alter_info Alter_info describing which columns, defaults or | ||
| 14568 | indexes are dropped or modified. | ||
| 14569 | |||
| 14570 | @return | ||
| 14571 | true The field is used by generated column/default or functional | ||
| 14572 | index, error was reported. | ||
| 14573 | false Otherwise. | ||
| 14574 | |||
| 14575 | */ | ||
| 14576 | 3676 | static bool check_if_field_used_by_generated_column_or_default( | |
| 14577 | TABLE *table, const Field *field, const Alter_info *alter_info) { | ||
| 14578 | 3676 | MY_BITMAP dependent_fields; | |
| 14579 | my_bitmap_map bitbuf[bitmap_buffer_size(MAX_FIELDS) / sizeof(my_bitmap_map)]; | ||
| 14580 |
1/2✓ Branch 0 taken 3676 times.
✗ Branch 1 not taken.
|
3676 | bitmap_init(&dependent_fields, bitbuf, table->s->fields); |
| 14581 | 3676 | MY_BITMAP *save_old_read_set = table->read_set; | |
| 14582 | 3676 | table->read_set = &dependent_fields; | |
| 14583 | |||
| 14584 |
2/2✓ Branch 0 taken 21091 times.
✓ Branch 1 taken 3658 times.
|
24749 | for (Field **vfield_ptr = table->field; *vfield_ptr; vfield_ptr++) { |
| 14585 | 21091 | Field *vfield = *vfield_ptr; | |
| 14586 |
6/6✓ Branch 0 taken 20053 times.
✓ Branch 1 taken 1038 times.
✓ Branch 2 taken 202 times.
✓ Branch 3 taken 19851 times.
✓ Branch 4 taken 1240 times.
✓ Branch 5 taken 19851 times.
|
41144 | if (vfield->is_gcol() || |
| 14587 | 20053 | vfield->has_insert_default_general_value_expression()) { | |
| 14588 | /* | ||
| 14589 | Ignore generated columns (including hidden columns for functional | ||
| 14590 | indexes) and columns with generated defaults which are going to | ||
| 14591 | be dropped. | ||
| 14592 | */ | ||
| 14593 |
4/6✓ Branch 0 taken 1240 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1240 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 325 times.
✓ Branch 5 taken 915 times.
|
1240 | if (std::any_of(alter_info->drop_list.cbegin(), |
| 14594 | alter_info->drop_list.cend(), | ||
| 14595 | 2872 | [vfield](const Alter_drop *drop) { | |
| 14596 |
2/2✓ Branch 0 taken 1100 times.
✓ Branch 1 taken 672 times.
|
2872 | return drop->type == Alter_drop::COLUMN && |
| 14597 |
2/2✓ Branch 0 taken 325 times.
✓ Branch 1 taken 775 times.
|
2872 | !my_strcasecmp(system_charset_info, |
| 14598 | vfield->field_name, drop->name); | ||
| 14599 | })) | ||
| 14600 | 351 | continue; | |
| 14601 | |||
| 14602 | /* | ||
| 14603 | Ignore generated default values which are removed or changed. | ||
| 14604 | |||
| 14605 | If new default value is dependent on removed/renamed column | ||
| 14606 | the problem will be detected and reported as error later. | ||
| 14607 | */ | ||
| 14608 |
3/4✓ Branch 0 taken 184 times.
✓ Branch 1 taken 731 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 915 times.
|
1099 | if (vfield->has_insert_default_general_value_expression() && |
| 14609 |
4/8✓ Branch 0 taken 184 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 184 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 184 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 184 times.
|
184 | std::any_of(alter_info->alter_list.cbegin(), |
| 14610 | alter_info->alter_list.cend(), | ||
| 14611 | 4 | [vfield](const Alter_column *alter) { | |
| 14612 | 4 | return (alter->change_type() == | |
| 14613 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | Alter_column::Type::SET_DEFAULT || |
| 14614 | 4 | alter->change_type() == | |
| 14615 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
8 | Alter_column::Type::DROP_DEFAULT) && |
| 14616 |
0/2✗ Branch 0 not taken.
✗ Branch 1 not taken.
|
4 | !my_strcasecmp(system_charset_info, |
| 14617 | vfield->field_name, alter->name); | ||
| 14618 | })) | ||
| 14619 | ✗ | continue; | |
| 14620 | |||
| 14621 | /* | ||
| 14622 | Ignore columns which are explicitly mentioned in CHANGE/MODIFY | ||
| 14623 | clauses in this ALTER TABLE and thus have new generation expression | ||
| 14624 | or default. | ||
| 14625 | |||
| 14626 | Again if such new expression is dependent on removed/renamed column | ||
| 14627 | the problem will be detected and reported as error later. | ||
| 14628 | */ | ||
| 14629 |
5/8✓ Branch 0 taken 915 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 915 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 915 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 26 times.
✓ Branch 7 taken 889 times.
|
915 | if (std::any_of(alter_info->create_list.cbegin(), |
| 14630 | alter_info->create_list.cend(), | ||
| 14631 | 424 | [vfield](const Create_field &def) { | |
| 14632 |
2/2✓ Branch 0 taken 191 times.
✓ Branch 1 taken 42 times.
|
424 | return (def.change && |
| 14633 |
2/2✓ Branch 0 taken 26 times.
✓ Branch 1 taken 165 times.
|
191 | !my_strcasecmp(system_charset_info, |
| 14634 | 233 | vfield->field_name, def.change)); | |
| 14635 | })) | ||
| 14636 | 26 | continue; | |
| 14637 | |||
| 14638 |
5/8✓ Branch 0 taken 709 times.
✓ Branch 1 taken 180 times.
✓ Branch 2 taken 709 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 180 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 180 times.
✗ Branch 7 not taken.
|
889 | assert((vfield->gcol_info && vfield->gcol_info->expr_item) || |
| 14639 | (vfield->m_default_val_expr && | ||
| 14640 | vfield->m_default_val_expr->expr_item)); | ||
| 14641 | 889 | Mark_field mark_fld(MARK_COLUMNS_TEMP); | |
| 14642 |
2/2✓ Branch 0 taken 709 times.
✓ Branch 1 taken 180 times.
|
889 | Item *expr = vfield->is_gcol() ? vfield->gcol_info->expr_item |
| 14643 | 180 | : vfield->m_default_val_expr->expr_item; | |
| 14644 |
1/2✓ Branch 0 taken 889 times.
✗ Branch 1 not taken.
|
889 | expr->walk(&Item::mark_field_in_map, enum_walk::PREFIX, |
| 14645 | reinterpret_cast<uchar *>(&mark_fld)); | ||
| 14646 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 871 times.
|
889 | if (bitmap_is_set(table->read_set, field->field_index())) { |
| 14647 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 12 times.
|
18 | if (vfield->is_gcol()) { |
| 14648 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
|
6 | if (vfield->is_field_for_functional_index()) |
| 14649 | 2 | my_error(ER_DEPENDENT_BY_FUNCTIONAL_INDEX, MYF(0), | |
| 14650 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | field->field_name); |
| 14651 | else | ||
| 14652 | 4 | my_error(ER_DEPENDENT_BY_GENERATED_COLUMN, MYF(0), | |
| 14653 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | field->field_name); |
| 14654 | } else { | ||
| 14655 | 12 | my_error(ER_DEPENDENT_BY_DEFAULT_GENERATED_VALUE, MYF(0), | |
| 14656 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | field->field_name, table->alias); |
| 14657 | } | ||
| 14658 | 18 | table->read_set = save_old_read_set; | |
| 14659 | 18 | return true; | |
| 14660 | } | ||
| 14661 | } | ||
| 14662 | } | ||
| 14663 | |||
| 14664 | 3658 | table->read_set = save_old_read_set; | |
| 14665 | 3658 | return false; | |
| 14666 | } | ||
| 14667 | |||
| 14668 | // Prepare Create_field and Key_spec objects for ALTER and upgrade. | ||
| 14669 | 95231 | bool prepare_fields_and_keys(THD *thd, const dd::Table *src_table, TABLE *table, | |
| 14670 | HA_CREATE_INFO *create_info, | ||
| 14671 | Alter_info *alter_info, Alter_table_ctx *alter_ctx, | ||
| 14672 | const uint &used_fields) { | ||
| 14673 | /* New column definitions are added here */ | ||
| 14674 | 95231 | List<Create_field> new_create_list; | |
| 14675 | /* New key definitions are added here */ | ||
| 14676 |
1/2✓ Branch 0 taken 95231 times.
✗ Branch 1 not taken.
|
95231 | Mem_root_array<Key_spec *> new_key_list(thd->mem_root); |
| 14677 | |||
| 14678 | /* | ||
| 14679 | Original Alter_info::drop_list is used by foreign key handling code and | ||
| 14680 | storage engines. check_if_field_used_by_generated_column_or_default() | ||
| 14681 | also needs original Alter_info::drop_list. So this function should not | ||
| 14682 | modify original list but rather work with its copy. | ||
| 14683 | */ | ||
| 14684 | Prealloced_array<const Alter_drop *, 1> drop_list( | ||
| 14685 | PSI_INSTRUMENT_ME, alter_info->drop_list.cbegin(), | ||
| 14686 |
2/4✓ Branch 0 taken 95231 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 95231 times.
✗ Branch 3 not taken.
|
95231 | alter_info->drop_list.cend()); |
| 14687 | |||
| 14688 | /* | ||
| 14689 | Alter_info::alter_rename_key_list is also used by fill_alter_inplace_info() | ||
| 14690 | call. So this function should not modify original list but rather work with | ||
| 14691 | its copy. | ||
| 14692 | */ | ||
| 14693 | Prealloced_array<const Alter_rename_key *, 1> rename_key_list( | ||
| 14694 | PSI_INSTRUMENT_ME, alter_info->alter_rename_key_list.cbegin(), | ||
| 14695 |
3/6✓ Branch 0 taken 95231 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 95231 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 95231 times.
✗ Branch 5 not taken.
|
95231 | alter_info->alter_rename_key_list.cend()); |
| 14696 | |||
| 14697 | /* | ||
| 14698 | This is how we check that all indexes to be altered are name-resolved: We | ||
| 14699 | make a copy of the list from the alter_info, and remove all the indexes | ||
| 14700 | that are found in the table. Later we check that there is nothing left in | ||
| 14701 | the list. This is obviously just a copy-paste of what is done for renamed | ||
| 14702 | indexes. | ||
| 14703 | */ | ||
| 14704 | Prealloced_array<const Alter_index_visibility *, 1> index_visibility_list( | ||
| 14705 | PSI_INSTRUMENT_ME, alter_info->alter_index_visibility_list.cbegin(), | ||
| 14706 |
3/6✓ Branch 0 taken 95231 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 95231 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 95231 times.
✗ Branch 5 not taken.
|
95231 | alter_info->alter_index_visibility_list.cend()); |
| 14707 | |||
| 14708 | /* List with secondary keys which should be created after copying the data */ | ||
| 14709 |
1/2✓ Branch 0 taken 95231 times.
✗ Branch 1 not taken.
|
95231 | Mem_root_array<const Key_spec *> delayed_key_list(thd->mem_root); |
| 14710 | /* | ||
| 14711 | Alter_info::alter_list is used by fill_alter_inplace_info() call as well. | ||
| 14712 | So this function works on its copy rather than original list. | ||
| 14713 | */ | ||
| 14714 | Prealloced_array<const Alter_column *, 1> alter_list( | ||
| 14715 | PSI_INSTRUMENT_ME, alter_info->alter_list.cbegin(), | ||
| 14716 |
3/6✓ Branch 0 taken 95231 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 95231 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 95231 times.
✗ Branch 5 not taken.
|
95231 | alter_info->alter_list.cend()); |
| 14717 | |||
| 14718 |
1/2✓ Branch 0 taken 95231 times.
✗ Branch 1 not taken.
|
95231 | List_iterator<Create_field> def_it(alter_info->create_list); |
| 14719 |
1/2✓ Branch 0 taken 95231 times.
✗ Branch 1 not taken.
|
95231 | List_iterator<Create_field> find_it(new_create_list); |
| 14720 |
1/2✓ Branch 0 taken 95231 times.
✗ Branch 1 not taken.
|
95231 | List_iterator<Create_field> field_it(new_create_list); |
| 14721 | 95231 | List<Key_part_spec> key_parts; | |
| 14722 | 95231 | KEY *key_info = table->key_info; | |
| 14723 | |||
| 14724 |
1/2✓ Branch 0 taken 95231 times.
✗ Branch 1 not taken.
|
95231 | DBUG_TRACE; |
| 14725 | |||
| 14726 | /* | ||
| 14727 | During upgrade from 5.7, old tables are temporarily accessed to | ||
| 14728 | get the keys and fields, and in this process, we assign | ||
| 14729 | table->record[0] = table->s->default_values, hence, we make the | ||
| 14730 | call to restore_record() below conditional to avoid valgrind errors | ||
| 14731 | due to overlapping source and destination for memcpy. | ||
| 14732 | */ | ||
| 14733 |
2/2✓ Branch 0 taken 90926 times.
✓ Branch 1 taken 4305 times.
|
95231 | if (table->record[0] != table->s->default_values) |
| 14734 | 90926 | restore_record(table, s->default_values); // Empty record for DEFAULT | |
| 14735 | |||
| 14736 | 95231 | std::vector<Create_field *> functional_index_columns; | |
| 14737 | Create_field *def; | ||
| 14738 | |||
| 14739 | /* | ||
| 14740 | First collect all fields from table which isn't in drop_list | ||
| 14741 | */ | ||
| 14742 | Field **f_ptr, *field; | ||
| 14743 |
2/2✓ Branch 0 taken 974403 times.
✓ Branch 1 taken 95171 times.
|
1069574 | for (f_ptr = table->field; (field = *f_ptr); f_ptr++) { |
| 14744 | /* Check if field should be dropped */ | ||
| 14745 | 974403 | size_t i = 0; | |
| 14746 |
3/4✓ Branch 0 taken 1021025 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 49787 times.
✓ Branch 3 taken 971238 times.
|
1021025 | while (i < drop_list.size()) { |
| 14747 |
1/2✓ Branch 0 taken 49787 times.
✗ Branch 1 not taken.
|
49787 | const Alter_drop *drop = drop_list[i]; |
| 14748 |
4/4✓ Branch 0 taken 12387 times.
✓ Branch 1 taken 37400 times.
✓ Branch 2 taken 3165 times.
✓ Branch 3 taken 46622 times.
|
62174 | if (drop->type == Alter_drop::COLUMN && |
| 14749 |
3/4✓ Branch 0 taken 12387 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3165 times.
✓ Branch 3 taken 9222 times.
|
12387 | !my_strcasecmp(system_charset_info, field->field_name, drop->name)) { |
| 14750 | /* Reset auto_increment value if it was dropped */ | ||
| 14751 |
2/2✓ Branch 0 taken 35 times.
✓ Branch 1 taken 3130 times.
|
3165 | if ((field->auto_flags & Field::NEXT_NUMBER) && |
| 14752 |
2/2✓ Branch 0 taken 29 times.
✓ Branch 1 taken 6 times.
|
35 | !(used_fields & HA_CREATE_USED_AUTO)) { |
| 14753 | 29 | create_info->auto_increment_value = 0; | |
| 14754 | 29 | create_info->used_fields |= HA_CREATE_USED_AUTO; | |
| 14755 | } | ||
| 14756 | |||
| 14757 | /* | ||
| 14758 | If a generated column or a default expression is dependent | ||
| 14759 | on this column, this column cannot be dropped. | ||
| 14760 | |||
| 14761 | The same applies to case when this table is partitioned and | ||
| 14762 | we drop column used by partitioning function. | ||
| 14763 | */ | ||
| 14764 |
1/2✓ Branch 0 taken 3165 times.
✗ Branch 1 not taken.
|
3165 | if (check_if_field_used_by_generated_column_or_default(table, field, |
| 14765 |
4/4✓ Branch 0 taken 3158 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 3155 times.
|
6323 | alter_info) || |
| 14766 |
3/4✓ Branch 0 taken 3158 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 3155 times.
|
3158 | check_if_field_used_by_partitioning_func(table, field, alter_info)) |
| 14767 | 10 | return true; | |
| 14768 | |||
| 14769 | 3155 | break; // Column was found. | |
| 14770 | } | ||
| 14771 | 46622 | i++; | |
| 14772 | } | ||
| 14773 |
3/4✓ Branch 0 taken 974393 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3155 times.
✓ Branch 3 taken 971238 times.
|
974393 | if (i < drop_list.size()) { |
| 14774 |
1/2✓ Branch 0 taken 3155 times.
✗ Branch 1 not taken.
|
3155 | drop_list.erase(i); |
| 14775 | 3155 | continue; | |
| 14776 | } | ||
| 14777 | /* Check if field is changed */ | ||
| 14778 | 971238 | def_it.rewind(); | |
| 14779 |
2/2✓ Branch 0 taken 1133325 times.
✓ Branch 1 taken 941112 times.
|
2074437 | while ((def = def_it++)) { |
| 14780 |
4/4✓ Branch 0 taken 587786 times.
✓ Branch 1 taken 545539 times.
✓ Branch 2 taken 30126 times.
✓ Branch 3 taken 1103199 times.
|
1721111 | if (def->change && |
| 14781 |
3/4✓ Branch 0 taken 587786 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30126 times.
✓ Branch 3 taken 557660 times.
|
587786 | !my_strcasecmp(system_charset_info, field->field_name, def->change)) |
| 14782 | 30126 | break; | |
| 14783 | } | ||
| 14784 |
2/2✓ Branch 0 taken 30126 times.
✓ Branch 1 taken 941112 times.
|
971238 | if (def) { // Field is changed |
| 14785 | 30126 | def->field = field; | |
| 14786 |
1/2✓ Branch 0 taken 30126 times.
✗ Branch 1 not taken.
|
30126 | def->charset = get_sql_field_charset(def, create_info); |
| 14787 | |||
| 14788 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 30123 times.
|
30126 | if (field->stored_in_db != def->stored_in_db) { |
| 14789 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | my_error(ER_UNSUPPORTED_ACTION_ON_GENERATED_COLUMN, MYF(0), |
| 14790 | "Changing the STORED status"); | ||
| 14791 | 3 | return true; | |
| 14792 | } | ||
| 14793 | |||
| 14794 | /* | ||
| 14795 | If a generated column or a default expression is dependent | ||
| 14796 | on this column, this column cannot be renamed. | ||
| 14797 | |||
| 14798 | The same applies to case when this table is partitioned and | ||
| 14799 | we rename column used by partitioning function. | ||
| 14800 | */ | ||
| 14801 |
1/2✓ Branch 0 taken 30123 times.
✗ Branch 1 not taken.
|
30123 | if ((my_strcasecmp(system_charset_info, def->field_name, def->change) != |
| 14802 |
4/4✓ Branch 0 taken 422 times.
✓ Branch 1 taken 29701 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 30116 times.
|
30545 | 0) && |
| 14803 |
3/4✓ Branch 0 taken 422 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 417 times.
✓ Branch 3 taken 5 times.
|
422 | (check_if_field_used_by_generated_column_or_default(table, field, |
| 14804 | 417 | alter_info) || | |
| 14805 |
3/4✓ Branch 0 taken 417 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 415 times.
|
417 | check_if_field_used_by_partitioning_func(table, field, alter_info))) |
| 14806 | 7 | return true; | |
| 14807 | |||
| 14808 | /* | ||
| 14809 | Add column being updated to the list of new columns. | ||
| 14810 | Note that columns with AFTER clauses are added to the end | ||
| 14811 | of the list for now. Their positions will be corrected later. | ||
| 14812 | */ | ||
| 14813 |
1/2✓ Branch 0 taken 30116 times.
✗ Branch 1 not taken.
|
30116 | new_create_list.push_back(def); |
| 14814 | |||
| 14815 | /* | ||
| 14816 | If the new column type is GEOMETRY (or a subtype) NOT NULL, | ||
| 14817 | and the old column type is nullable and not GEOMETRY (or a | ||
| 14818 | subtype), existing NULL values will be converted into empty | ||
| 14819 | strings in non-strict mode. Empty strings are illegal values | ||
| 14820 | in GEOMETRY columns. | ||
| 14821 | |||
| 14822 | However, generated columns have implicit default values, so they can be | ||
| 14823 | NOT NULL. | ||
| 14824 | */ | ||
| 14825 | 60356 | if (def->sql_type == MYSQL_TYPE_GEOMETRY && | |
| 14826 |
2/2✓ Branch 0 taken 63 times.
✓ Branch 1 taken 61 times.
|
124 | (def->flags & (NO_DEFAULT_VALUE_FLAG | NOT_NULL_FLAG)) && |
| 14827 |
5/6✓ Branch 0 taken 63 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 48 times.
✓ Branch 4 taken 13 times.
✓ Branch 5 taken 2 times.
|
63 | field->type() != MYSQL_TYPE_GEOMETRY && field->is_nullable() && |
| 14828 |
8/8✓ Branch 0 taken 124 times.
✓ Branch 1 taken 29992 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 4 times.
✓ Branch 7 taken 30112 times.
|
30240 | !thd->is_strict_mode() && !def->is_gcol()) { |
| 14829 | 4 | alter_ctx->error_if_not_empty |= | |
| 14830 | Alter_table_ctx::GEOMETRY_WITHOUT_DEFAULT; | ||
| 14831 | } | ||
| 14832 | } else { | ||
| 14833 | /* | ||
| 14834 | This field was not dropped and the definition is not changed, add | ||
| 14835 | it to the list for the new table. | ||
| 14836 | */ | ||
| 14837 |
2/4✓ Branch 0 taken 941112 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 941112 times.
✗ Branch 3 not taken.
|
941112 | def = new (thd->mem_root) Create_field(field, field); |
| 14838 | |||
| 14839 | // Mark if collation was specified explicitly by user for the column. | ||
| 14840 | 941112 | const dd::Table *obj = | |
| 14841 |
2/2✓ Branch 0 taken 8232 times.
✓ Branch 1 taken 932880 times.
|
941112 | (table->s->tmp_table ? table->s->tmp_table_def : src_table); |
| 14842 | // In case of upgrade, we do not have src_table. | ||
| 14843 |
2/2✓ Branch 0 taken 27852 times.
✓ Branch 1 taken 913260 times.
|
941112 | if (!obj) |
| 14844 | 27852 | def->is_explicit_collation = false; | |
| 14845 | else | ||
| 14846 | 1826520 | def->is_explicit_collation = | |
| 14847 |
3/6✓ Branch 0 taken 913260 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 913260 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 913260 times.
✗ Branch 5 not taken.
|
913260 | obj->get_column(field->field_name)->is_explicit_collation(); |
| 14848 | |||
| 14849 | // If we have a replication setup _and_ the master doesn't sort | ||
| 14850 | // functional index columns last in the table, we will not do it either. | ||
| 14851 | // Otherwise, we will position the functional index columns last in the | ||
| 14852 | // table, sorted on their name. | ||
| 14853 |
7/8✓ Branch 0 taken 941112 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 314 times.
✓ Branch 3 taken 940798 times.
✓ Branch 4 taken 313 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 313 times.
✓ Branch 7 taken 940799 times.
|
941426 | if (is_field_for_functional_index(def) && |
| 14854 | 314 | is_not_slave_or_master_sorts_functional_index_columns_last( | |
| 14855 | thd->variables.original_server_version)) { | ||
| 14856 |
1/2✓ Branch 0 taken 313 times.
✗ Branch 1 not taken.
|
313 | functional_index_columns.push_back(def); |
| 14857 | } else { | ||
| 14858 |
1/2✓ Branch 0 taken 940799 times.
✗ Branch 1 not taken.
|
940799 | new_create_list.push_back(def); |
| 14859 | } | ||
| 14860 | |||
| 14861 |
3/4✓ Branch 0 taken 941112 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 40 times.
✓ Branch 3 taken 941072 times.
|
941112 | if (alter_column_name_default_or_visibility(alter_info, &alter_list, def)) |
| 14862 | 40 | return true; | |
| 14863 | } | ||
| 14864 | } | ||
| 14865 | 95171 | def_it.rewind(); | |
| 14866 |
2/2✓ Branch 0 taken 61244 times.
✓ Branch 1 taken 94997 times.
|
156241 | while ((def = def_it++)) // Add new columns |
| 14867 | { | ||
| 14868 |
4/4✓ Branch 0 taken 30285 times.
✓ Branch 1 taken 30959 times.
✓ Branch 2 taken 169 times.
✓ Branch 3 taken 30116 times.
|
61244 | if (def->change && !def->field) { |
| 14869 | 169 | my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change, | |
| 14870 |
1/2✓ Branch 0 taken 169 times.
✗ Branch 1 not taken.
|
169 | table->s->table_name.str); |
| 14871 | 169 | return true; | |
| 14872 | } | ||
| 14873 | |||
| 14874 |
1/2✓ Branch 0 taken 61075 times.
✗ Branch 1 not taken.
|
61075 | warn_on_deprecated_float_auto_increment(thd, *def); |
| 14875 | |||
| 14876 | /* | ||
| 14877 | If this ALTER TABLE doesn't have an AFTER clause for the modified | ||
| 14878 | column then it doesn't need further processing. | ||
| 14879 | */ | ||
| 14880 |
4/4✓ Branch 0 taken 30116 times.
✓ Branch 1 taken 30959 times.
✓ Branch 2 taken 26168 times.
✓ Branch 3 taken 3948 times.
|
61075 | if (def->change && !def->after) continue; |
| 14881 | |||
| 14882 | /* | ||
| 14883 | New columns of type DATE/DATETIME/GEOMETRIC with NOT NULL constraint | ||
| 14884 | added as part of ALTER operation will generate zero date for DATE/ | ||
| 14885 | DATETIME types and empty string for GEOMETRIC types when the table | ||
| 14886 | is not empty. Hence certain additional checks needs to be performed | ||
| 14887 | as described below. This cannot be caught by SE(For INPLACE ALTER) | ||
| 14888 | since it checks for only NULL value. Zero date and empty string | ||
| 14889 | does not violate the NOT NULL value constraint. | ||
| 14890 | */ | ||
| 14891 |
2/2✓ Branch 0 taken 30959 times.
✓ Branch 1 taken 3948 times.
|
34907 | if (!def->change) { |
| 14892 | /* | ||
| 14893 | Check that the DATE/DATETIME NOT NULL field we are going to | ||
| 14894 | add either has a default value, is a generated column, or the | ||
| 14895 | date '0000-00-00' is allowed by the set sql mode. | ||
| 14896 | |||
| 14897 | If the '0000-00-00' value isn't allowed then raise the | ||
| 14898 | error_if_not_empty flag to allow ALTER TABLE only if the table to be | ||
| 14899 | altered is empty. | ||
| 14900 | */ | ||
| 14901 | 92877 | if ((def->sql_type == MYSQL_TYPE_DATE || | |
| 14902 |
2/2✓ Branch 0 taken 30757 times.
✓ Branch 1 taken 202 times.
|
30959 | def->sql_type == MYSQL_TYPE_NEWDATE || |
| 14903 |
1/2✓ Branch 0 taken 30757 times.
✗ Branch 1 not taken.
|
30757 | def->sql_type == MYSQL_TYPE_DATETIME || |
| 14904 |
2/2✓ Branch 0 taken 68 times.
✓ Branch 1 taken 30689 times.
|
30757 | def->sql_type == MYSQL_TYPE_DATETIME2) && |
| 14905 |
7/8✓ Branch 0 taken 30959 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 268 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 256 times.
✓ Branch 5 taken 12 times.
✓ Branch 6 taken 111 times.
✓ Branch 7 taken 30848 times.
|
62174 | !alter_ctx->datetime_field && !def->is_gcol() && |
| 14906 |
2/2✓ Branch 0 taken 111 times.
✓ Branch 1 taken 145 times.
|
256 | !(~def->flags & (NO_DEFAULT_VALUE_FLAG | NOT_NULL_FLAG))) { |
| 14907 | 111 | alter_ctx->datetime_field = def; | |
| 14908 | 111 | alter_ctx->error_if_not_empty |= | |
| 14909 | Alter_table_ctx::DATETIME_WITHOUT_DEFAULT; | ||
| 14910 | } | ||
| 14911 | |||
| 14912 | /* | ||
| 14913 | New GEOMETRY (and subtypes) columns can't be NOT NULL unless they have a | ||
| 14914 | default value. Explicit default values are currently not supported for | ||
| 14915 | geometry columns. To add a GEOMETRY NOT NULL column, first create a | ||
| 14916 | GEOMETRY NULL column, UPDATE the table to set a different value than | ||
| 14917 | NULL, and then do a ALTER TABLE MODIFY COLUMN to set NOT NULL. | ||
| 14918 | |||
| 14919 | This restriction can be lifted once MySQL supports explicit default | ||
| 14920 | values (i.e., functions) for geometry columns. The new restriction would | ||
| 14921 | then be for added GEOMETRY NOT NULL columns to always have a provided | ||
| 14922 | default value. | ||
| 14923 | |||
| 14924 | Generated columns (including generated geometry columns) have implicit | ||
| 14925 | default values, so they can be NOT NULL. | ||
| 14926 | */ | ||
| 14927 |
6/6✓ Branch 0 taken 77 times.
✓ Branch 1 taken 30882 times.
✓ Branch 2 taken 36 times.
✓ Branch 3 taken 41 times.
✓ Branch 4 taken 26 times.
✓ Branch 5 taken 30933 times.
|
30995 | if (def->sql_type == MYSQL_TYPE_GEOMETRY && !def->is_gcol() && |
| 14928 |
2/2✓ Branch 0 taken 26 times.
✓ Branch 1 taken 10 times.
|
36 | (def->flags & (NO_DEFAULT_VALUE_FLAG | NOT_NULL_FLAG))) { |
| 14929 | 26 | alter_ctx->error_if_not_empty |= | |
| 14930 | Alter_table_ctx::GEOMETRY_WITHOUT_DEFAULT; | ||
| 14931 | } | ||
| 14932 | } | ||
| 14933 | |||
| 14934 |
2/2✓ Branch 0 taken 21359 times.
✓ Branch 1 taken 13548 times.
|
34907 | if (!def->after) |
| 14935 |
1/2✓ Branch 0 taken 21359 times.
✗ Branch 1 not taken.
|
21359 | new_create_list.push_back(def); |
| 14936 | else { | ||
| 14937 | const Create_field *find; | ||
| 14938 |
2/2✓ Branch 0 taken 3948 times.
✓ Branch 1 taken 9600 times.
|
13548 | if (def->change) { |
| 14939 | 3948 | find_it.rewind(); | |
| 14940 | /* | ||
| 14941 | For columns being modified with AFTER clause we should first remove | ||
| 14942 | these columns from the list and then add them back at their correct | ||
| 14943 | positions. | ||
| 14944 | */ | ||
| 14945 |
1/2✓ Branch 0 taken 100999 times.
✗ Branch 1 not taken.
|
100999 | while ((find = find_it++)) { |
| 14946 | /* | ||
| 14947 | Create_fields representing changed columns are added directly | ||
| 14948 | from Alter_info::create_list to new_create_list. We can therefore | ||
| 14949 | safely use pointer equality rather than name matching here. | ||
| 14950 | This prevents removing the wrong column in case of column rename. | ||
| 14951 | */ | ||
| 14952 |
2/2✓ Branch 0 taken 3948 times.
✓ Branch 1 taken 97051 times.
|
100999 | if (find == def) { |
| 14953 |
1/2✓ Branch 0 taken 3948 times.
✗ Branch 1 not taken.
|
3948 | find_it.remove(); |
| 14954 | 3948 | break; | |
| 14955 | } | ||
| 14956 | } | ||
| 14957 | } | ||
| 14958 |
2/2✓ Branch 0 taken 1759 times.
✓ Branch 1 taken 11789 times.
|
13548 | if (def->after == first_keyword) |
| 14959 |
1/2✓ Branch 0 taken 1759 times.
✗ Branch 1 not taken.
|
1759 | new_create_list.push_front(def); |
| 14960 | else { | ||
| 14961 | 11789 | find_it.rewind(); | |
| 14962 |
2/2✓ Branch 0 taken 250135 times.
✓ Branch 1 taken 5 times.
|
250140 | while ((find = find_it++)) { |
| 14963 |
3/4✓ Branch 0 taken 250135 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11784 times.
✓ Branch 3 taken 238351 times.
|
250135 | if (!my_strcasecmp(system_charset_info, def->after, find->field_name)) |
| 14964 | 11784 | break; | |
| 14965 | } | ||
| 14966 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 11784 times.
|
11789 | if (!find) { |
| 14967 | 5 | my_error(ER_BAD_FIELD_ERROR, MYF(0), def->after, | |
| 14968 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | table->s->table_name.str); |
| 14969 | 5 | return true; | |
| 14970 | } | ||
| 14971 |
1/2✓ Branch 0 taken 11784 times.
✗ Branch 1 not taken.
|
11784 | find_it.after(def); // Put column after this |
| 14972 | } | ||
| 14973 | } | ||
| 14974 | } | ||
| 14975 |
3/4✓ Branch 0 taken 94997 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 94993 times.
|
94997 | if (alter_list.size() > 0) { |
| 14976 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | my_error(ER_BAD_FIELD_ERROR, MYF(0), alter_list[0]->name, |
| 14977 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | table->s->table_name.str); |
| 14978 | 4 | return true; | |
| 14979 | } | ||
| 14980 | |||
| 14981 | // Ensure that hidden generated column for functional indexes are inserted at | ||
| 14982 | // the end, sorted by their column name. | ||
| 14983 |
1/2✓ Branch 0 taken 94993 times.
✗ Branch 1 not taken.
|
94993 | std::sort(functional_index_columns.begin(), functional_index_columns.end(), |
| 14984 | 354 | [](const Create_field *a, const Create_field *b) { | |
| 14985 | 354 | return my_strcasecmp(system_charset_info, a->field_name, | |
| 14986 | 354 | b->field_name) < 0; | |
| 14987 | }); | ||
| 14988 | |||
| 14989 |
2/2✓ Branch 0 taken 313 times.
✓ Branch 1 taken 94993 times.
|
95306 | for (Create_field *ic_field : functional_index_columns) { |
| 14990 |
1/2✓ Branch 0 taken 313 times.
✗ Branch 1 not taken.
|
313 | new_create_list.push_back(ic_field); |
| 14991 | } | ||
| 14992 | |||
| 14993 |
2/2✓ Branch 0 taken 40 times.
✓ Branch 1 taken 94953 times.
|
94993 | if (!new_create_list.elements) { |
| 14994 |
1/2✓ Branch 0 taken 40 times.
✗ Branch 1 not taken.
|
40 | my_error(ER_CANT_REMOVE_ALL_FIELDS, MYF(0)); |
| 14995 | 40 | return true; | |
| 14996 | } | ||
| 14997 | |||
| 14998 | // Make sure generated invisible primary key column is at the first position. | ||
| 14999 |
2/4✓ Branch 0 taken 94953 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 94953 times.
|
94953 | if (adjust_generated_invisible_primary_key_column_position( |
| 15000 | thd, create_info->db_type, table, &new_create_list)) | ||
| 15001 | ✗ | return true; | |
| 15002 | |||
| 15003 | /* | ||
| 15004 | Collect all keys which isn't in drop list. Add only those | ||
| 15005 | for which some fields exists. | ||
| 15006 | |||
| 15007 | We also store secondary keys in delayed_key_list to make use of | ||
| 15008 | the InnoDB fast index creation. The following conditions must be | ||
| 15009 | met: | ||
| 15010 | |||
| 15011 | - fast_index_creation is enabled for the current session | ||
| 15012 | - expand_fast_index_creation is enabled for the current session; | ||
| 15013 | - we are going to create an InnoDB table (this is checked later when the | ||
| 15014 | target engine is known); | ||
| 15015 | - the key most be a non-UNIQUE one; | ||
| 15016 | - there are no foreign keys. This can be optimized later to exclude only | ||
| 15017 | those keys which are a part of foreign key constraints. Currently we | ||
| 15018 | simply disable this optimization for all keys if there are any foreign | ||
| 15019 | key constraints in the table. | ||
| 15020 | */ | ||
| 15021 | |||
| 15022 | 94953 | const dd::Table *obj = | |
| 15023 |
2/2✓ Branch 0 taken 1245 times.
✓ Branch 1 taken 93708 times.
|
94953 | (table->s->tmp_table ? table->s->tmp_table_def : src_table); |
| 15024 |
3/4✓ Branch 0 taken 5 times.
✓ Branch 1 taken 94948 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
94958 | bool skip_secondary = thd->variables.expand_fast_index_creation && |
| 15025 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | (obj == nullptr || obj->foreign_key_parents().empty()); |
| 15026 | |||
| 15027 |
2/2✓ Branch 0 taken 102515 times.
✓ Branch 1 taken 94950 times.
|
197465 | for (uint i = 0; i < table->s->keys; i++, key_info++) { |
| 15028 | 102515 | const char *key_name = key_info->name; | |
| 15029 | 102515 | bool index_column_dropped = false; | |
| 15030 | 102515 | size_t drop_idx = 0; | |
| 15031 |
3/4✓ Branch 0 taken 109066 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14520 times.
✓ Branch 3 taken 94546 times.
|
109066 | while (drop_idx < drop_list.size()) { |
| 15032 |
1/2✓ Branch 0 taken 14520 times.
✗ Branch 1 not taken.
|
14520 | const Alter_drop *drop = drop_list[drop_idx]; |
| 15033 |
4/4✓ Branch 0 taken 14263 times.
✓ Branch 1 taken 257 times.
✓ Branch 2 taken 7969 times.
✓ Branch 3 taken 6551 times.
|
28783 | if (drop->type == Alter_drop::KEY && |
| 15034 |
3/4✓ Branch 0 taken 14263 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7969 times.
✓ Branch 3 taken 6294 times.
|
14263 | !my_strcasecmp(system_charset_info, key_name, drop->name)) |
| 15035 | 7969 | break; | |
| 15036 | 6551 | drop_idx++; | |
| 15037 | } | ||
| 15038 |
3/4✓ Branch 0 taken 102515 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7969 times.
✓ Branch 3 taken 94546 times.
|
102515 | if (drop_idx < drop_list.size()) { |
| 15039 |
1/2✓ Branch 0 taken 7969 times.
✗ Branch 1 not taken.
|
7969 | drop_list.erase(drop_idx); |
| 15040 | 7969 | continue; | |
| 15041 | } | ||
| 15042 | |||
| 15043 | 94546 | KEY_PART_INFO *key_part = key_info->key_part; | |
| 15044 | 94546 | key_parts.clear(); | |
| 15045 |
2/2✓ Branch 0 taken 153400 times.
✓ Branch 1 taken 94546 times.
|
247946 | for (uint j = 0; j < key_info->user_defined_key_parts; j++, key_part++) { |
| 15046 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 153400 times.
|
153400 | if (!key_part->field) continue; // Wrong field (from UNIREG) |
| 15047 | 153400 | const char *key_part_name = key_part->field->field_name; | |
| 15048 | const Create_field *cfield; | ||
| 15049 | 153400 | field_it.rewind(); | |
| 15050 |
2/2✓ Branch 0 taken 613582 times.
✓ Branch 1 taken 160 times.
|
613742 | while ((cfield = field_it++)) { |
| 15051 |
2/2✓ Branch 0 taken 21073 times.
✓ Branch 1 taken 592509 times.
|
613582 | if (cfield->change) { |
| 15052 |
3/4✓ Branch 0 taken 21073 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6579 times.
✓ Branch 3 taken 14494 times.
|
21073 | if (!my_strcasecmp(system_charset_info, key_part_name, |
| 15053 | cfield->change)) | ||
| 15054 | 6579 | break; | |
| 15055 |
3/4✓ Branch 0 taken 592509 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 146661 times.
✓ Branch 3 taken 445848 times.
|
592509 | } else if (!my_strcasecmp(system_charset_info, key_part_name, |
| 15056 | cfield->field_name)) | ||
| 15057 | 146661 | break; | |
| 15058 | } | ||
| 15059 |
2/2✓ Branch 0 taken 160 times.
✓ Branch 1 taken 153240 times.
|
153400 | if (!cfield) { |
| 15060 | /* | ||
| 15061 | We are dropping a column associated with an index. | ||
| 15062 | */ | ||
| 15063 | 160 | index_column_dropped = true; | |
| 15064 | 160 | continue; // Field is removed | |
| 15065 | } | ||
| 15066 | 153240 | uint key_part_length = key_part->length; | |
| 15067 |
2/2✓ Branch 0 taken 153071 times.
✓ Branch 1 taken 169 times.
|
153240 | if (cfield->field) // Not new field |
| 15068 | { | ||
| 15069 | /* | ||
| 15070 | If the field can't have only a part used in a key according to its | ||
| 15071 | new type, or should not be used partially according to its | ||
| 15072 | previous type, or the field length is less than the key part | ||
| 15073 | length, unset the key part length. | ||
| 15074 | |||
| 15075 | We also unset the key part length if it is the same as the | ||
| 15076 | old field's length, so the whole new field will be used. | ||
| 15077 | |||
| 15078 | BLOBs may have cfield->length == 0, which is why we test it before | ||
| 15079 | checking whether cfield->length < key_part_length (in chars). | ||
| 15080 | |||
| 15081 | In case of TEXTs we check the data type maximum length *in bytes* | ||
| 15082 | to key part length measured *in characters* (i.e. key_part_length | ||
| 15083 | divided to mbmaxlen). This is because it's OK to have: | ||
| 15084 | CREATE TABLE t1 (a tinytext, key(a(254)) character set utf8); | ||
| 15085 | In case of this example: | ||
| 15086 | - data type maximum length is 255. | ||
| 15087 | - key_part_length is 1016 (=254*4, where 4 is mbmaxlen) | ||
| 15088 | */ | ||
| 15089 |
2/4✓ Branch 0 taken 153071 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 153071 times.
✗ Branch 3 not taken.
|
153071 | if (!Field::type_can_have_key_part(cfield->field->type()) || |
| 15090 |
3/4✓ Branch 0 taken 102666 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 100823 times.
✓ Branch 3 taken 1843 times.
|
102666 | !Field::type_can_have_key_part(cfield->sql_type) || |
| 15091 | /* spatial keys can't have sub-key length */ | ||
| 15092 |
2/2✓ Branch 0 taken 100691 times.
✓ Branch 1 taken 132 times.
|
100823 | (key_info->flags & HA_SPATIAL) || |
| 15093 |
2/2✓ Branch 0 taken 95838 times.
✓ Branch 1 taken 4853 times.
|
100691 | (cfield->field->field_length == key_part_length && |
| 15094 |
7/8✓ Branch 0 taken 102666 times.
✓ Branch 1 taken 50405 times.
✓ Branch 2 taken 95838 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 252 times.
✓ Branch 5 taken 95586 times.
✓ Branch 6 taken 147966 times.
✓ Branch 7 taken 5105 times.
|
255989 | key_part->field->type() != MYSQL_TYPE_BLOB) || |
| 15095 |
2/4✓ Branch 0 taken 5105 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5105 times.
✗ Branch 3 not taken.
|
5105 | (cfield->max_display_width_in_codepoints() && |
| 15096 | 9975 | (((cfield->sql_type >= MYSQL_TYPE_TINY_BLOB && | |
| 15097 |
2/2✓ Branch 0 taken 4809 times.
✓ Branch 1 taken 61 times.
|
4870 | cfield->sql_type <= MYSQL_TYPE_BLOB) |
| 15098 |
2/2✓ Branch 0 taken 4870 times.
✓ Branch 1 taken 235 times.
|
9914 | ? blob_length_by_type(cfield->sql_type) |
| 15099 |
1/2✓ Branch 0 taken 296 times.
✗ Branch 1 not taken.
|
296 | : cfield->max_display_width_in_codepoints()) < |
| 15100 |
2/4✓ Branch 0 taken 5105 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5105 times.
|
5105 | key_part_length / key_part->field->charset()->mbmaxlen))) |
| 15101 | 147966 | key_part_length = 0; // Use whole field | |
| 15102 | } | ||
| 15103 |
1/2✓ Branch 0 taken 153240 times.
✗ Branch 1 not taken.
|
153240 | key_part_length /= key_part->field->charset()->mbmaxlen; |
| 15104 | // The Key_part_spec constructor differentiates between explicit ascending | ||
| 15105 | // (ORDER_ASC) and implicit ascending order (ORDER_NOT_RELEVANT). However, | ||
| 15106 | // here we only have HA_REVERSE_SORT to base our ordering decision on. The | ||
| 15107 | // only known case where the difference matters is in case of indexes on | ||
| 15108 | // geometry columns and typed arrays, which can't have explicit ordering. | ||
| 15109 | // Therefore, in such cases we pass ORDER_NOT_RELEVANT. | ||
| 15110 | enum_order order = | ||
| 15111 | 153240 | key_part->key_part_flag & HA_REVERSE_SORT | |
| 15112 |
2/2✓ Branch 0 taken 152844 times.
✓ Branch 1 taken 396 times.
|
306084 | ? ORDER_DESC |
| 15113 |
1/2✓ Branch 0 taken 152844 times.
✗ Branch 1 not taken.
|
152844 | : ((key_part->field->type() == MYSQL_TYPE_GEOMETRY || |
| 15114 |
3/4✓ Branch 0 taken 152712 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 157 times.
✓ Branch 3 taken 152555 times.
|
152712 | key_part->field->is_array()) |
| 15115 |
2/2✓ Branch 0 taken 152712 times.
✓ Branch 1 taken 132 times.
|
305556 | ? ORDER_NOT_RELEVANT |
| 15116 | 153240 | : ORDER_ASC); | |
| 15117 |
2/2✓ Branch 0 taken 323 times.
✓ Branch 1 taken 152917 times.
|
153240 | if (key_part->field->is_field_for_functional_index()) { |
| 15118 |
1/2✓ Branch 0 taken 323 times.
✗ Branch 1 not taken.
|
323 | key_parts.push_back(new (thd->mem_root) Key_part_spec( |
| 15119 |
1/2✓ Branch 0 taken 323 times.
✗ Branch 1 not taken.
|
323 | cfield->field_name, key_part->field->gcol_info->expr_item, order)); |
| 15120 | } else { | ||
| 15121 |
1/2✓ Branch 0 taken 152917 times.
✗ Branch 1 not taken.
|
152917 | key_parts.push_back(new (thd->mem_root) Key_part_spec( |
| 15122 |
1/2✓ Branch 0 taken 152917 times.
✗ Branch 1 not taken.
|
305834 | to_lex_cstring(cfield->field_name), key_part_length, order)); |
| 15123 | } | ||
| 15124 | } | ||
| 15125 |
2/2✓ Branch 0 taken 94445 times.
✓ Branch 1 taken 101 times.
|
94546 | if (key_parts.elements) { |
| 15126 | 94445 | KEY_CREATE_INFO key_create_info(key_info->is_visible); | |
| 15127 | |||
| 15128 | keytype key_type; | ||
| 15129 | |||
| 15130 | /* If this index is to stay in the table check if it has to be renamed. */ | ||
| 15131 |
3/4✓ Branch 0 taken 94865 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 578 times.
✓ Branch 3 taken 94287 times.
|
94865 | for (size_t rename_idx = 0; rename_idx < rename_key_list.size(); |
| 15132 | rename_idx++) { | ||
| 15133 |
1/2✓ Branch 0 taken 578 times.
✗ Branch 1 not taken.
|
578 | const Alter_rename_key *rename_key = rename_key_list[rename_idx]; |
| 15134 |
3/4✓ Branch 0 taken 578 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 158 times.
✓ Branch 3 taken 420 times.
|
578 | if (!my_strcasecmp(system_charset_info, key_name, |
| 15135 | rename_key->old_name)) { | ||
| 15136 |
3/4✓ Branch 0 taken 158 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 157 times.
|
158 | if (!my_strcasecmp(system_charset_info, key_name, primary_key_name)) { |
| 15137 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), rename_key->old_name); |
| 15138 | 3 | return true; | |
| 15139 |
3/4✓ Branch 0 taken 157 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 156 times.
|
157 | } else if (!my_strcasecmp(system_charset_info, rename_key->new_name, |
| 15140 | primary_key_name)) { | ||
| 15141 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), rename_key->new_name); |
| 15142 | 1 | return true; | |
| 15143 | } | ||
| 15144 | |||
| 15145 | 156 | key_name = rename_key->new_name; | |
| 15146 |
1/2✓ Branch 0 taken 156 times.
✗ Branch 1 not taken.
|
156 | rename_key_list.erase(rename_idx); |
| 15147 | /* | ||
| 15148 | If the user has explicitly renamed the key, we should no longer | ||
| 15149 | treat it as generated. Otherwise this key might be automatically | ||
| 15150 | dropped by mysql_prepare_create_table() and this will confuse | ||
| 15151 | code in fill_alter_inplace_info(). | ||
| 15152 | */ | ||
| 15153 | 156 | key_info->flags &= ~HA_GENERATED_KEY; | |
| 15154 | 156 | break; | |
| 15155 | } | ||
| 15156 | } | ||
| 15157 | |||
| 15158 | // Erase all alter operations that operate on this index. | ||
| 15159 |
1/2✓ Branch 0 taken 94443 times.
✗ Branch 1 not taken.
|
94443 | for (auto it = index_visibility_list.begin(); |
| 15160 |
3/4✓ Branch 0 taken 94580 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 137 times.
✓ Branch 3 taken 94443 times.
|
94580 | it < index_visibility_list.end();) |
| 15161 |
3/4✓ Branch 0 taken 137 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 102 times.
✓ Branch 3 taken 35 times.
|
137 | if (my_strcasecmp(system_charset_info, key_name, (*it)->name()) == 0) |
| 15162 |
1/2✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
|
102 | index_visibility_list.erase(it); |
| 15163 | else | ||
| 15164 | 35 | ++it; | |
| 15165 | |||
| 15166 |
2/2✓ Branch 0 taken 106 times.
✓ Branch 1 taken 94337 times.
|
94443 | if (key_info->is_algorithm_explicit) { |
| 15167 | 106 | key_create_info.algorithm = key_info->algorithm; | |
| 15168 | 106 | key_create_info.is_algorithm_explicit = true; | |
| 15169 | } else { | ||
| 15170 | /* | ||
| 15171 | If key algorithm was not specified explicitly for source table | ||
| 15172 | don't specify one a new version as well, This allows to handle | ||
| 15173 | ALTER TABLEs which change SE nicely. | ||
| 15174 | OTOH this means that any ALTER TABLE will rebuild such keys when | ||
| 15175 | SE changes default algorithm for key. Code will have to be adjusted | ||
| 15176 | to handle such situation more gracefully. | ||
| 15177 | */ | ||
| 15178 |
2/4✓ Branch 0 taken 94337 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 94337 times.
✗ Branch 3 not taken.
|
94337 | assert((key_create_info.is_algorithm_explicit == false) && |
| 15179 | (key_create_info.algorithm == HA_KEY_ALG_SE_SPECIFIC)); | ||
| 15180 | } | ||
| 15181 | |||
| 15182 |
2/2✓ Branch 0 taken 261 times.
✓ Branch 1 taken 94182 times.
|
94443 | if (key_info->flags & HA_USES_BLOCK_SIZE) |
| 15183 | 261 | key_create_info.block_size = key_info->block_size; | |
| 15184 |
2/2✓ Branch 0 taken 873 times.
✓ Branch 1 taken 93570 times.
|
94443 | if (key_info->flags & HA_USES_PARSER) |
| 15185 | 873 | key_create_info.parser_name = *plugin_name(key_info->parser); | |
| 15186 |
2/2✓ Branch 0 taken 273 times.
✓ Branch 1 taken 94170 times.
|
94443 | if (key_info->flags & HA_USES_COMMENT) |
| 15187 | 273 | key_create_info.comment = key_info->comment; | |
| 15188 | |||
| 15189 |
2/2✓ Branch 0 taken 89100 times.
✓ Branch 1 taken 5343 times.
|
94443 | if (key_info->engine_attribute.str != nullptr) |
| 15190 | 89100 | key_create_info.m_engine_attribute = key_info->engine_attribute; | |
| 15191 | |||
| 15192 |
2/2✓ Branch 0 taken 89100 times.
✓ Branch 1 taken 5343 times.
|
94443 | if (key_info->secondary_engine_attribute.str != nullptr) |
| 15193 | 89100 | key_create_info.m_secondary_engine_attribute = | |
| 15194 | key_info->secondary_engine_attribute; | ||
| 15195 | |||
| 15196 | 94589 | for (const Alter_index_visibility *alter_index_visibility : | |
| 15197 |
2/2✓ Branch 0 taken 147 times.
✓ Branch 1 taken 94442 times.
|
189032 | alter_info->alter_index_visibility_list) { |
| 15198 | 147 | const char *name = alter_index_visibility->name(); | |
| 15199 |
3/4✓ Branch 0 taken 147 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 102 times.
✓ Branch 3 taken 45 times.
|
147 | if (my_strcasecmp(system_charset_info, key_name, name) == 0) { |
| 15200 |
1/2✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
|
102 | if (table->s->primary_key <= MAX_KEY && |
| 15201 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 101 times.
|
102 | table->key_info + table->s->primary_key == key_info) { |
| 15202 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_PK_INDEX_CANT_BE_INVISIBLE, MYF(0)); |
| 15203 | 1 | return true; | |
| 15204 | } | ||
| 15205 | 101 | key_create_info.is_visible = alter_index_visibility->is_visible(); | |
| 15206 | } | ||
| 15207 | } | ||
| 15208 | |||
| 15209 |
2/2✓ Branch 0 taken 132 times.
✓ Branch 1 taken 94310 times.
|
94442 | if (key_info->flags & HA_SPATIAL) |
| 15210 | 132 | key_type = KEYTYPE_SPATIAL; | |
| 15211 |
2/2✓ Branch 0 taken 70662 times.
✓ Branch 1 taken 23648 times.
|
94310 | else if (key_info->flags & HA_NOSAME) { |
| 15212 |
3/4✓ Branch 0 taken 70662 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 57688 times.
✓ Branch 3 taken 12974 times.
|
70662 | if (!my_strcasecmp(system_charset_info, key_name, primary_key_name)) |
| 15213 | 57688 | key_type = KEYTYPE_PRIMARY; | |
| 15214 | else | ||
| 15215 | 12974 | key_type = KEYTYPE_UNIQUE; | |
| 15216 |
2/2✓ Branch 0 taken 1168 times.
✓ Branch 1 taken 22480 times.
|
23648 | } else if (key_info->flags & HA_FULLTEXT) |
| 15217 | 1168 | key_type = KEYTYPE_FULLTEXT; | |
| 15218 | else | ||
| 15219 | 22480 | key_type = KEYTYPE_MULTIPLE; | |
| 15220 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 94442 times.
|
94442 | if (key_info->flags & HA_CLUSTERING) |
| 15221 | ✗ | key_type = static_cast<enum keytype>(key_type | KEYTYPE_CLUSTERING); | |
| 15222 | |||
| 15223 | /* | ||
| 15224 | If we have dropped a column associated with an index, | ||
| 15225 | this warrants a check for duplicate indexes | ||
| 15226 | */ | ||
| 15227 | Key_spec *const key = new (thd->mem_root) | ||
| 15228 | 94442 | Key_spec(thd->mem_root, key_type, to_lex_cstring(key_name), | |
| 15229 | 94442 | &key_create_info, (key_info->flags & HA_GENERATED_KEY), | |
| 15230 |
2/4✓ Branch 0 taken 94442 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 94442 times.
✗ Branch 3 not taken.
|
94442 | index_column_dropped, key_parts); |
| 15231 |
1/2✓ Branch 0 taken 94442 times.
✗ Branch 1 not taken.
|
94442 | new_key_list.push_back(key); |
| 15232 |
4/4✓ Branch 0 taken 5 times.
✓ Branch 1 taken 94437 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 1 times.
|
94442 | if (skip_secondary && key_type & KEYTYPE_MULTIPLE) { |
| 15233 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | delayed_key_list.push_back(key); |
| 15234 | } | ||
| 15235 | } | ||
| 15236 | } | ||
| 15237 | { | ||
| 15238 |
1/2✓ Branch 0 taken 94950 times.
✗ Branch 1 not taken.
|
94950 | new_key_list.reserve(new_key_list.size() + alter_info->key_list.size()); |
| 15239 |
2/2✓ Branch 0 taken 17057 times.
✓ Branch 1 taken 94950 times.
|
112007 | for (size_t i = 0; i < alter_info->key_list.size(); i++) { |
| 15240 |
1/2✓ Branch 0 taken 17057 times.
✗ Branch 1 not taken.
|
17057 | Key_spec *const key = alter_info->key_list[i]; |
| 15241 |
1/2✓ Branch 0 taken 17057 times.
✗ Branch 1 not taken.
|
17057 | new_key_list.push_back(key); // Add new keys |
| 15242 |
2/2✓ Branch 0 taken 16803 times.
✓ Branch 1 taken 254 times.
|
17057 | if (key->type != KEYTYPE_FOREIGN) { |
| 15243 |
3/4✓ Branch 0 taken 3 times.
✓ Branch 1 taken 16800 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
16803 | if (skip_secondary && key->type & KEYTYPE_MULTIPLE) { |
| 15244 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | delayed_key_list.push_back(key); |
| 15245 | } | ||
| 15246 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 254 times.
|
254 | } else if (skip_secondary) { |
| 15247 | /* | ||
| 15248 | We are adding a foreign key so disable the secondary keys | ||
| 15249 | optimization. | ||
| 15250 | */ | ||
| 15251 | ✗ | skip_secondary = false; | |
| 15252 | ✗ | delayed_key_list.clear(); | |
| 15253 | } | ||
| 15254 | } | ||
| 15255 | } | ||
| 15256 | |||
| 15257 | /* | ||
| 15258 | Copy existing foreign keys from the source table into | ||
| 15259 | Alter_table_ctx so that they can be added to the new table | ||
| 15260 | later. Omits foreign keys to be dropped and removes them | ||
| 15261 | from the drop_list. Checks that foreign keys to be kept | ||
| 15262 | are still valid. | ||
| 15263 | */ | ||
| 15264 |
2/2✓ Branch 0 taken 72969 times.
✓ Branch 1 taken 21981 times.
|
94950 | if (create_info->db_type->flags & HTON_SUPPORTS_FOREIGN_KEYS) { |
| 15265 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 72963 times.
|
72969 | if (transfer_preexisting_foreign_keys( |
| 15266 |
1/2✓ Branch 0 taken 72969 times.
✗ Branch 1 not taken.
|
72969 | thd, src_table, table->s->db.str, table->s->table_name.str, |
| 15267 |
1/2✓ Branch 0 taken 72969 times.
✗ Branch 1 not taken.
|
72969 | table->s->db_type(), alter_info, &new_create_list, alter_ctx, |
| 15268 | &drop_list)) | ||
| 15269 | 6 | return true; | |
| 15270 | } | ||
| 15271 | |||
| 15272 |
3/4✓ Branch 0 taken 94944 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 929 times.
✓ Branch 3 taken 94015 times.
|
94944 | if (drop_list.size() > 0) { |
| 15273 | // Now this contains only DROP for not-found objects. | ||
| 15274 |
4/6✓ Branch 0 taken 929 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 929 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 993 times.
✓ Branch 5 taken 54 times.
|
1047 | for (const Alter_drop *drop : drop_list) { |
| 15275 |
4/5✓ Branch 0 taken 13 times.
✓ Branch 1 taken 866 times.
✓ Branch 2 taken 43 times.
✓ Branch 3 taken 71 times.
✗ Branch 4 not taken.
|
993 | switch (drop->type) { |
| 15276 | 13 | case Alter_drop::FOREIGN_KEY: | |
| 15277 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 9 times.
|
13 | if (!(create_info->db_type->flags & HTON_SUPPORTS_FOREIGN_KEYS)) { |
| 15278 | /* | ||
| 15279 | For historical reasons we silently ignore attempts to drop | ||
| 15280 | foreign keys from tables in storage engines which don't | ||
| 15281 | support them. This is in sync with the fact that attempts | ||
| 15282 | to add foreign keys to such tables are silently ignored | ||
| 15283 | as well. Once the latter is changed the former hack can | ||
| 15284 | be removed as well. | ||
| 15285 | */ | ||
| 15286 | 4 | break; | |
| 15287 | } | ||
| 15288 | [[fallthrough]]; | ||
| 15289 | case Alter_drop::KEY: | ||
| 15290 | case Alter_drop::COLUMN: | ||
| 15291 |
1/2✓ Branch 0 taken 875 times.
✗ Branch 1 not taken.
|
875 | my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0), drop->name); |
| 15292 | 875 | return true; | |
| 15293 | 43 | case Alter_drop::CHECK_CONSTRAINT: | |
| 15294 | /* | ||
| 15295 | Check constraints to be dropped are already handled by the | ||
| 15296 | prepare_check_constraints_for_alter(). | ||
| 15297 | */ | ||
| 15298 | 43 | break; | |
| 15299 | 71 | case Alter_drop::ANY_CONSTRAINT: | |
| 15300 | /* | ||
| 15301 | Constraint type is resolved by name and a new Alter_drop element | ||
| 15302 | with resolved type is added to the Alter_drop list. | ||
| 15303 | Alter_drop::ANY_CONSTRAINT element is retained in the Alter_drop | ||
| 15304 | list to support re-execution of stored routine or prepared | ||
| 15305 | statement. | ||
| 15306 | */ | ||
| 15307 | 71 | break; | |
| 15308 | ✗ | default: | |
| 15309 | ✗ | assert(false); | |
| 15310 | break; | ||
| 15311 | } | ||
| 15312 | } | ||
| 15313 | } | ||
| 15314 | |||
| 15315 |
3/4✓ Branch 0 taken 94069 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 37 times.
✓ Branch 3 taken 94032 times.
|
94069 | if (rename_key_list.size() > 0) { |
| 15316 |
1/2✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
|
37 | my_error(ER_KEY_DOES_NOT_EXITS, MYF(0), rename_key_list[0]->old_name, |
| 15317 |
1/2✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
|
37 | table->s->table_name.str); |
| 15318 | 37 | return true; | |
| 15319 | } | ||
| 15320 |
3/4✓ Branch 0 taken 94032 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 94028 times.
|
94032 | if (index_visibility_list.size() > 0) { |
| 15321 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | my_error(ER_KEY_DOES_NOT_EXITS, MYF(0), index_visibility_list[0]->name(), |
| 15322 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | table->s->table_name.str); |
| 15323 | 4 | return true; | |
| 15324 | } | ||
| 15325 | |||
| 15326 | 94028 | alter_info->create_list.swap(new_create_list); | |
| 15327 |
1/2✓ Branch 0 taken 94028 times.
✗ Branch 1 not taken.
|
94028 | alter_info->key_list.clear(); |
| 15328 |
1/2✓ Branch 0 taken 94028 times.
✗ Branch 1 not taken.
|
94028 | alter_info->key_list.resize(new_key_list.size()); |
| 15329 |
1/2✓ Branch 0 taken 94028 times.
✗ Branch 1 not taken.
|
94028 | std::copy(new_key_list.begin(), new_key_list.end(), |
| 15330 | alter_info->key_list.begin()); | ||
| 15331 |
1/2✓ Branch 0 taken 94028 times.
✗ Branch 1 not taken.
|
94028 | alter_info->delayed_key_list.clear(); |
| 15332 |
1/2✓ Branch 0 taken 94028 times.
✗ Branch 1 not taken.
|
94028 | alter_info->delayed_key_list.resize(delayed_key_list.size()); |
| 15333 |
3/6✓ Branch 0 taken 94028 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 94028 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 94028 times.
✗ Branch 5 not taken.
|
94028 | std::copy(delayed_key_list.cbegin(), delayed_key_list.cend(), |
| 15334 | alter_info->delayed_key_list.begin()); | ||
| 15335 | |||
| 15336 | 94028 | return false; | |
| 15337 | 95231 | } | |
| 15338 | |||
| 15339 | /** | ||
| 15340 | Prepare column and key definitions for CREATE TABLE in ALTER TABLE. | ||
| 15341 | |||
| 15342 | This function transforms parse output of ALTER TABLE - lists of | ||
| 15343 | columns and keys to add, drop or modify into, essentially, | ||
| 15344 | CREATE TABLE definition - a list of columns and keys of the new | ||
| 15345 | table. While doing so, it also performs some (bug not all) | ||
| 15346 | semantic checks. | ||
| 15347 | |||
| 15348 | This function is invoked when we know that we're going to | ||
| 15349 | perform ALTER TABLE via a temporary table -- i.e. in-place ALTER TABLE | ||
| 15350 | is not possible, perhaps because the ALTER statement contains | ||
| 15351 | instructions that require change in table data, not only in | ||
| 15352 | table definition or indexes. | ||
| 15353 | |||
| 15354 | @param[in,out] thd thread handle. Used as a memory pool | ||
| 15355 | and source of environment information. | ||
| 15356 | @param[in] src_table DD table object for the table to be | ||
| 15357 | created/altered. Will be nullptr for temporary tables. | ||
| 15358 | @param[in] table the source table, open and locked | ||
| 15359 | Used as an interface to the storage engine | ||
| 15360 | to acquire additional information about | ||
| 15361 | the original table. | ||
| 15362 | @param[in,out] create_info A blob with CREATE/ALTER TABLE | ||
| 15363 | parameters | ||
| 15364 | @param[in,out] alter_info Another blob with ALTER/CREATE parameters. | ||
| 15365 | Originally create_info was used only in | ||
| 15366 | CREATE TABLE and alter_info only in ALTER TABLE. | ||
| 15367 | But since ALTER might end-up doing CREATE, | ||
| 15368 | this distinction is gone and we just carry | ||
| 15369 | around two structures. | ||
| 15370 | @param[in,out] alter_ctx Runtime context for ALTER TABLE. | ||
| 15371 | |||
| 15372 | @return | ||
| 15373 | Fills various create_info members based on information retrieved | ||
| 15374 | from the storage engine. | ||
| 15375 | Sets create_info->varchar if the table has a VARCHAR column. | ||
| 15376 | Prepares alter_info->create_list and alter_info->key_list with | ||
| 15377 | columns and keys of the new table. | ||
| 15378 | @retval true error, out of memory or a semantical error in ALTER | ||
| 15379 | TABLE instructions | ||
| 15380 | @retval false success | ||
| 15381 | */ | ||
| 15382 | |||
| 15383 | 90926 | bool mysql_prepare_alter_table(THD *thd, const dd::Table *src_table, | |
| 15384 | TABLE *table, HA_CREATE_INFO *create_info, | ||
| 15385 | Alter_info *alter_info, | ||
| 15386 | Alter_table_ctx *alter_ctx) { | ||
| 15387 | 90926 | uint db_create_options = | |
| 15388 | 90926 | (table->s->db_create_options & ~(HA_OPTION_PACK_RECORD)); | |
| 15389 | 90926 | uint64_t used_fields = create_info->used_fields; | |
| 15390 | |||
| 15391 |
1/2✓ Branch 0 taken 90926 times.
✗ Branch 1 not taken.
|
90926 | DBUG_TRACE; |
| 15392 | |||
| 15393 | // Prepare data in HA_CREATE_INFO shared by ALTER and upgrade code. | ||
| 15394 |
1/2✓ Branch 0 taken 90926 times.
✗ Branch 1 not taken.
|
90926 | create_info->init_create_options_from_share(table->s, used_fields); |
| 15395 | |||
| 15396 |
4/4✓ Branch 0 taken 90680 times.
✓ Branch 1 taken 246 times.
✓ Branch 2 taken 5691 times.
✓ Branch 3 taken 84989 times.
|
90926 | if (!(used_fields & HA_CREATE_USED_AUTO) && table->found_next_number_field) { |
| 15397 | /* Table has an autoincrement, copy value to new table */ | ||
| 15398 |
1/2✓ Branch 0 taken 5691 times.
✗ Branch 1 not taken.
|
5691 | table->file->info(HA_STATUS_AUTO); |
| 15399 | 5691 | create_info->auto_increment_value = table->file->stats.auto_increment_value; | |
| 15400 | } | ||
| 15401 | |||
| 15402 | // Encryption was changed to not KEYRING and ALTER does not contain | ||
| 15403 | // encryption_key_id mark encryption_key_id as not set then | ||
| 15404 |
2/2✓ Branch 0 taken 4655 times.
✓ Branch 1 taken 86271 times.
|
90926 | if (used_fields & HA_CREATE_USED_ENCRYPT && |
| 15405 |
2/2✓ Branch 0 taken 4653 times.
✓ Branch 1 taken 2 times.
|
4655 | 0 != strncmp(create_info->encrypt_type.str, "KEYRING", |
| 15406 | 4653 | create_info->encrypt_type.length) && | |
| 15407 |
1/2✓ Branch 0 taken 4653 times.
✗ Branch 1 not taken.
|
4653 | !(used_fields & HA_CREATE_USED_ENCRYPTION_KEY_ID)) { |
| 15408 | 4653 | create_info->used_fields &= ~(HA_CREATE_USED_ENCRYPTION_KEY_ID); | |
| 15409 | 4653 | create_info->was_encryption_key_id_set = false; | |
| 15410 | } | ||
| 15411 | |||
| 15412 |
3/4✓ Branch 0 taken 90926 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1203 times.
✓ Branch 3 taken 89723 times.
|
90926 | if (prepare_fields_and_keys(thd, src_table, table, create_info, alter_info, |
| 15413 | alter_ctx, used_fields)) | ||
| 15414 | 1203 | return true; | |
| 15415 | |||
| 15416 |
1/2✓ Branch 0 taken 89723 times.
✗ Branch 1 not taken.
|
89723 | table->file->update_create_info(create_info); |
| 15417 | |||
| 15418 | /* Get the autoextend_size value for the old table if the user did not | ||
| 15419 | specify it on the command line */ | ||
| 15420 |
7/8✓ Branch 0 taken 88478 times.
✓ Branch 1 taken 1245 times.
✓ Branch 2 taken 88478 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 68013 times.
✓ Branch 5 taken 20465 times.
✓ Branch 6 taken 68013 times.
✓ Branch 7 taken 21710 times.
|
89723 | if (src_table && src_table->engine() == "InnoDB") { |
| 15421 | 68013 | ulonglong autoextend_size{}; | |
| 15422 | |||
| 15423 |
1/2✓ Branch 0 taken 68013 times.
✗ Branch 1 not taken.
|
68013 | dd::get_implicit_tablespace_options(thd, src_table, &autoextend_size); |
| 15424 | |||
| 15425 |
2/2✓ Branch 0 taken 62979 times.
✓ Branch 1 taken 5034 times.
|
68013 | if (!create_info->m_implicit_tablespace_autoextend_size_change) { |
| 15426 | 62979 | create_info->m_implicit_tablespace_autoextend_size = autoextend_size; | |
| 15427 | } | ||
| 15428 | } | ||
| 15429 | |||
| 15430 | /* | ||
| 15431 | NDB storage engine misuses handler::update_create_info() to implement | ||
| 15432 | special handling of table comments which are used to specify and store | ||
| 15433 | some NDB-specific table options. In the process it might report error. | ||
| 15434 | In order to detect and correctly handle such situation we need to call | ||
| 15435 | THD::is_error(). | ||
| 15436 | */ | ||
| 15437 |
2/4✓ Branch 0 taken 89723 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 89723 times.
|
89723 | if (thd->is_error()) return true; |
| 15438 | |||
| 15439 |
2/2✓ Branch 0 taken 89706 times.
✓ Branch 1 taken 17 times.
|
89723 | if ((create_info->table_options & |
| 15440 | 89706 | (HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS)) || | |
| 15441 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 89704 times.
|
89706 | (used_fields & HA_CREATE_USED_PACK_KEYS)) |
| 15442 | 19 | db_create_options &= ~(HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS); | |
| 15443 |
2/2✓ Branch 0 taken 85688 times.
✓ Branch 1 taken 4035 times.
|
89723 | if ((create_info->table_options & |
| 15444 | 85688 | (HA_OPTION_STATS_PERSISTENT | HA_OPTION_NO_STATS_PERSISTENT)) || | |
| 15445 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 85683 times.
|
85688 | (used_fields & HA_CREATE_USED_STATS_PERSISTENT)) |
| 15446 | 4040 | db_create_options &= | |
| 15447 | ~(HA_OPTION_STATS_PERSISTENT | HA_OPTION_NO_STATS_PERSISTENT); | ||
| 15448 |
2/2✓ Branch 0 taken 17 times.
✓ Branch 1 taken 89706 times.
|
89723 | if (create_info->table_options & (HA_OPTION_CHECKSUM | HA_OPTION_NO_CHECKSUM)) |
| 15449 | 17 | db_create_options &= ~(HA_OPTION_CHECKSUM | HA_OPTION_NO_CHECKSUM); | |
| 15450 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 89717 times.
|
89723 | if (create_info->table_options & |
| 15451 | (HA_OPTION_DELAY_KEY_WRITE | HA_OPTION_NO_DELAY_KEY_WRITE)) | ||
| 15452 | 6 | db_create_options &= | |
| 15453 | ~(HA_OPTION_DELAY_KEY_WRITE | HA_OPTION_NO_DELAY_KEY_WRITE); | ||
| 15454 | 89723 | create_info->table_options |= db_create_options; | |
| 15455 | |||
| 15456 |
2/2✓ Branch 0 taken 1245 times.
✓ Branch 1 taken 88478 times.
|
89723 | if (table->s->tmp_table) create_info->options |= HA_LEX_CREATE_TMP_TABLE; |
| 15457 | |||
| 15458 | 89723 | return false; | |
| 15459 | 90926 | } | |
| 15460 | |||
| 15461 | /** | ||
| 15462 | Get Create_field object for newly created table by its name | ||
| 15463 | in the old version of table. | ||
| 15464 | |||
| 15465 | @param alter_info Alter_info describing newly created table. | ||
| 15466 | @param old_name Name of field in old table. | ||
| 15467 | |||
| 15468 | @returns Pointer to Create_field object, NULL - if field is | ||
| 15469 | not present in new version of table. | ||
| 15470 | */ | ||
| 15471 | |||
| 15472 | 67 | static const Create_field *get_field_by_old_name(Alter_info *alter_info, | |
| 15473 | const char *old_name) { | ||
| 15474 |
1/2✓ Branch 0 taken 67 times.
✗ Branch 1 not taken.
|
67 | List_iterator_fast<Create_field> new_field_it(alter_info->create_list); |
| 15475 | const Create_field *new_field; | ||
| 15476 | |||
| 15477 |
1/2✓ Branch 0 taken 145 times.
✗ Branch 1 not taken.
|
145 | while ((new_field = new_field_it++)) { |
| 15478 |
3/4✓ Branch 0 taken 145 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 67 times.
✓ Branch 3 taken 78 times.
|
290 | if (new_field->field && |
| 15479 |
3/4✓ Branch 0 taken 145 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 67 times.
✓ Branch 3 taken 78 times.
|
145 | (my_strcasecmp(system_charset_info, new_field->field->field_name, |
| 15480 | old_name) == 0)) | ||
| 15481 | 67 | break; | |
| 15482 | } | ||
| 15483 | 67 | return new_field; | |
| 15484 | } | ||
| 15485 | |||
| 15486 | /** Type of change to foreign key column, */ | ||
| 15487 | |||
| 15488 | enum class fk_column_change_type { | ||
| 15489 | NO_CHANGE, | ||
| 15490 | DATA_CHANGE, | ||
| 15491 | RENAMED, | ||
| 15492 | DROPPED, | ||
| 15493 | SAFE_FOR_PARENT | ||
| 15494 | }; | ||
| 15495 | |||
| 15496 | /** | ||
| 15497 | Check that ALTER TABLE's changes on columns of a foreign key are allowed. | ||
| 15498 | |||
| 15499 | @tparam F Function class which returns foreign key's | ||
| 15500 | referenced or referencing (depending on | ||
| 15501 | whether we check ALTER TABLE that changes | ||
| 15502 | parent or child table) column name by its | ||
| 15503 | index. | ||
| 15504 | |||
| 15505 | @param[in] thd Thread context. | ||
| 15506 | @param[in] alter_info Alter_info describing changes to be done | ||
| 15507 | by ALTER TABLE. | ||
| 15508 | @param[in] fk_col_count Number of columns in the foreign key. | ||
| 15509 | @param[in] fk_columns Object of F type bound to the specific foreign | ||
| 15510 | key for which check is carried out. | ||
| 15511 | @param[out] bad_column_name Name of field on which ALTER TABLE tries to | ||
| 15512 | do prohibited operation. | ||
| 15513 | |||
| 15514 | @note This function takes into account value of @@foreign_key_checks | ||
| 15515 | setting. | ||
| 15516 | |||
| 15517 | @retval NO_CHANGE No significant changes are to be done on | ||
| 15518 | foreign key columns. | ||
| 15519 | @retval DATA_CHANGE ALTER TABLE might result in value | ||
| 15520 | change in foreign key column (and | ||
| 15521 | foreign_key_checks is on). | ||
| 15522 | @retval ENAMED Foreign key column is renamed. | ||
| 15523 | @retval DROPPED Foreign key column is dropped. | ||
| 15524 | @retval SAFE_FOR_PARENT The column change is safe if this is a | ||
| 15525 | referenced column. | ||
| 15526 | */ | ||
| 15527 | |||
| 15528 | template <class F> | ||
| 15529 | 126 | static fk_column_change_type fk_check_column_changes( | |
| 15530 | THD *thd, Alter_info *alter_info, uint fk_col_count, const F &fk_columns, | ||
| 15531 | const char **bad_column_name) { | ||
| 15532 | 126 | *bad_column_name = nullptr; | |
| 15533 | |||
| 15534 |
2/2✓ Branch 0 taken 67 times.
✓ Branch 1 taken 60 times.
|
254 | for (uint i = 0; i < fk_col_count; ++i) { |
| 15535 | 134 | const char *column = fk_columns(i); | |
| 15536 | 134 | const Create_field *new_field = get_field_by_old_name(alter_info, column); | |
| 15537 | |||
| 15538 |
1/2✓ Branch 0 taken 67 times.
✗ Branch 1 not taken.
|
134 | if (new_field) { |
| 15539 | 134 | Field *old_field = new_field->field; | |
| 15540 | |||
| 15541 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 67 times.
|
134 | if (my_strcasecmp(system_charset_info, old_field->field_name, |
| 15542 | new_field->field_name)) { | ||
| 15543 | /* | ||
| 15544 | Copy algorithm doesn't support proper renaming of columns in | ||
| 15545 | the foreign key yet. At the moment we lack API which will tell | ||
| 15546 | SE that foreign keys should be updated to use new name of column | ||
| 15547 | like it happens in case of in-place algorithm. | ||
| 15548 | */ | ||
| 15549 | ✗ | *bad_column_name = column; | |
| 15550 | ✗ | return fk_column_change_type::RENAMED; | |
| 15551 | } | ||
| 15552 | |||
| 15553 | 134 | const auto fields_differ = | |
| 15554 | 134 | (old_field->is_equal(new_field) == IS_EQUAL_NO); | |
| 15555 | |||
| 15556 |
6/6✓ Branch 0 taken 64 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 36 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 62 times.
|
190 | if (fields_differ || ((new_field->flags & NOT_NULL_FLAG) && |
| 15557 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 26 times.
|
56 | !old_field->is_flag_set(NOT_NULL_FLAG))) { |
| 15558 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
|
10 | if (!(thd->variables.option_bits & OPTION_NO_FOREIGN_KEY_CHECKS)) { |
| 15559 | /* | ||
| 15560 | Column in a FK has changed significantly. Unless | ||
| 15561 | foreign_key_checks are off we prohibit this since this | ||
| 15562 | means values in this column might be changed by ALTER | ||
| 15563 | and thus referential integrity might be broken, | ||
| 15564 | */ | ||
| 15565 | 6 | *bad_column_name = column; | |
| 15566 | /* NULL to NOT NULL column change is safe for referenced columns */ | ||
| 15567 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
|
6 | return fields_differ ? fk_column_change_type::DATA_CHANGE |
| 15568 | 6 | : fk_column_change_type::SAFE_FOR_PARENT; | |
| 15569 | } | ||
| 15570 | } | ||
| 15571 |
2/4✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 64 times.
✗ Branch 3 not taken.
|
128 | assert(old_field->is_gcol() == new_field->is_gcol() && |
| 15572 | old_field->is_virtual_gcol() == new_field->is_virtual_gcol()); | ||
| 15573 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
128 | assert(!old_field->is_gcol() || old_field->gcol_expr_is_equal(new_field)); |
| 15574 | } else { | ||
| 15575 | /* | ||
| 15576 | Column in FK was dropped. Most likely this will break | ||
| 15577 | integrity constraints of InnoDB data-dictionary (and thus | ||
| 15578 | InnoDB will emit an error), so we prohibit this right away | ||
| 15579 | even if foreign_key_checks are off. | ||
| 15580 | This also includes a rare case when another field replaces | ||
| 15581 | field being dropped since it is easy to break referential | ||
| 15582 | integrity in this case. | ||
| 15583 | */ | ||
| 15584 | ✗ | *bad_column_name = column; | |
| 15585 | ✗ | return fk_column_change_type::DROPPED; | |
| 15586 | } | ||
| 15587 | } | ||
| 15588 | |||
| 15589 | 120 | return fk_column_change_type::NO_CHANGE; | |
| 15590 | } | ||
| 15591 | |||
| 15592 | /** | ||
| 15593 | Check if ALTER TABLE we are about to execute using COPY algorithm | ||
| 15594 | is not supported as it might break referential integrity. | ||
| 15595 | |||
| 15596 | @note If foreign_key_checks is disabled (=0), we allow to break | ||
| 15597 | referential integrity. But we still disallow some operations | ||
| 15598 | like dropping or renaming columns in foreign key since they | ||
| 15599 | are likely to break consistency of InnoDB data-dictionary | ||
| 15600 | and thus will end-up in error anyway. | ||
| 15601 | |||
| 15602 | @param[in] thd Thread context. | ||
| 15603 | @param[in] table_list TABLE_LIST element for the table to be altered. | ||
| 15604 | @param[in] table_def dd::Table for old version of table to be altered. | ||
| 15605 | @param[in] alter_info Lists of fields, keys to be changed, added | ||
| 15606 | or dropped. | ||
| 15607 | |||
| 15608 | @retval false Success. | ||
| 15609 | @retval true Error, ALTER - tries to do change which is not compatible | ||
| 15610 | with foreign key definitions on the table. | ||
| 15611 | */ | ||
| 15612 | |||
| 15613 | 20744 | static bool fk_check_copy_alter_table(THD *thd, TABLE_LIST *table_list, | |
| 15614 | const dd::Table *table_def, | ||
| 15615 | Alter_info *alter_info) { | ||
| 15616 |
1/2✓ Branch 0 taken 20744 times.
✗ Branch 1 not taken.
|
20744 | DBUG_TRACE; |
| 15617 | |||
| 15618 |
2/2✓ Branch 0 taken 1151 times.
✓ Branch 1 taken 19593 times.
|
20744 | if (!table_def) return false; // Must be a temporary table. |
| 15619 | |||
| 15620 |
3/4✓ Branch 0 taken 19593 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 19593 times.
|
19599 | for (const dd::Foreign_key_parent *fk_p : table_def->foreign_key_parents()) { |
| 15621 | /* | ||
| 15622 | First, check foreign keys in which table participates as parent. | ||
| 15623 | To get necessary information about such a foreign key we need to | ||
| 15624 | acquire dd::Table object describing child table. | ||
| 15625 | */ | ||
| 15626 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client()); |
| 15627 | const dd::Table *child_table_def; | ||
| 15628 | |||
| 15629 | bool self_ref_fk = | ||
| 15630 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | (my_strcasecmp(table_alias_charset, fk_p->child_schema_name().c_str(), |
| 15631 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
12 | table_list->db) == 0 && |
| 15632 |
3/4✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 5 times.
|
6 | my_strcasecmp(table_alias_charset, fk_p->child_table_name().c_str(), |
| 15633 | 6 | table_list->table_name) == 0); | |
| 15634 | |||
| 15635 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5 times.
|
6 | if (self_ref_fk) |
| 15636 | 1 | child_table_def = table_def; | |
| 15637 | else { | ||
| 15638 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
|
5 | if (thd->dd_client()->acquire(fk_p->child_schema_name(), |
| 15639 | fk_p->child_table_name(), &child_table_def)) | ||
| 15640 | ✗ | return true; | |
| 15641 | } | ||
| 15642 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | assert(child_table_def != nullptr); |
| 15643 | |||
| 15644 |
6/10✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 10 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 10 times.
✓ Branch 9 taken 6 times.
|
16 | for (const dd::Foreign_key *fk : child_table_def->foreign_keys()) { |
| 15645 | /* | ||
| 15646 | Skip all foreign keys except one which corresponds to the | ||
| 15647 | dd::Foreign_key_parent object being processed. | ||
| 15648 | */ | ||
| 15649 |
2/4✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
|
10 | if (my_strcasecmp(system_charset_info, fk_p->fk_name().c_str(), |
| 15650 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 6 times.
|
10 | fk->name().c_str()) != 0) |
| 15651 | 4 | continue; | |
| 15652 | |||
| 15653 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5 times.
|
6 | if (self_ref_fk) { |
| 15654 | /* | ||
| 15655 | Also skip all foreign keys which are to be dropped by this | ||
| 15656 | ALTER TABLE. This is possible when a foreign key has the | ||
| 15657 | same table as child and parent. | ||
| 15658 | */ | ||
| 15659 | 1 | bool is_dropped = false; | |
| 15660 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | for (const Alter_drop *drop : alter_info->drop_list) { |
| 15661 | /* Names of foreign keys in InnoDB are case-insensitive. */ | ||
| 15662 | ✗ | if ((drop->type == Alter_drop::FOREIGN_KEY) && | |
| 15663 | ✗ | (my_strcasecmp(system_charset_info, fk->name().c_str(), | |
| 15664 | drop->name) == 0)) { | ||
| 15665 | ✗ | is_dropped = true; | |
| 15666 | ✗ | break; | |
| 15667 | } | ||
| 15668 | } | ||
| 15669 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (is_dropped) continue; |
| 15670 | } | ||
| 15671 | |||
| 15672 | enum fk_column_change_type changes; | ||
| 15673 | const char *bad_column_name; | ||
| 15674 | |||
| 15675 | 6 | auto fk_columns_lambda = [fk](uint i) { | |
| 15676 | 6 | return fk->elements()[i]->referenced_column_name().c_str(); | |
| 15677 | 6 | }; | |
| 15678 |
2/4✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
|
6 | changes = fk_check_column_changes(thd, alter_info, fk->elements().size(), |
| 15679 | fk_columns_lambda, &bad_column_name); | ||
| 15680 | |||
| 15681 |
1/5✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
6 | switch (changes) { |
| 15682 | 6 | case fk_column_change_type::SAFE_FOR_PARENT: | |
| 15683 | case fk_column_change_type::NO_CHANGE: | ||
| 15684 | /* No significant changes. We can proceed with ALTER! */ | ||
| 15685 | 6 | break; | |
| 15686 | ✗ | case fk_column_change_type::DATA_CHANGE: { | |
| 15687 | char buff[NAME_LEN * 2 + 2]; | ||
| 15688 | ✗ | strxnmov(buff, sizeof(buff) - 1, fk_p->child_schema_name().c_str(), | |
| 15689 | ✗ | ".", fk_p->child_table_name().c_str(), NullS); | |
| 15690 | ✗ | my_error(ER_FK_COLUMN_CANNOT_CHANGE_CHILD, MYF(0), bad_column_name, | |
| 15691 | ✗ | fk->name().c_str(), buff); | |
| 15692 | ✗ | return true; | |
| 15693 | } | ||
| 15694 | ✗ | case fk_column_change_type::RENAMED: | |
| 15695 | ✗ | my_error( | |
| 15696 | ER_ALTER_OPERATION_NOT_SUPPORTED_REASON, MYF(0), "ALGORITHM=COPY", | ||
| 15697 | ER_THD(thd, ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_FK_RENAME), | ||
| 15698 | "ALGORITHM=INPLACE"); | ||
| 15699 | ✗ | return true; | |
| 15700 | ✗ | case fk_column_change_type::DROPPED: | |
| 15701 | /* | ||
| 15702 | Should already have been checked in | ||
| 15703 | transfer_preexisting_foreign_keys(). | ||
| 15704 | */ | ||
| 15705 | ✗ | assert(false); | |
| 15706 | ✗ | default: | |
| 15707 | ✗ | assert(0); | |
| 15708 | } | ||
| 15709 | } | ||
| 15710 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | } |
| 15711 | |||
| 15712 |
6/10✓ Branch 0 taken 19593 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19593 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 19593 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 78 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 78 times.
✓ Branch 9 taken 19591 times.
|
19669 | for (const dd::Foreign_key *fk : table_def->foreign_keys()) { |
| 15713 | /* | ||
| 15714 | Now, check foreign keys in which table participates as child. | ||
| 15715 | |||
| 15716 | Skip all foreign keys which are to be dropped by this ALTER TABLE. | ||
| 15717 | */ | ||
| 15718 | 78 | bool is_dropped = false; | |
| 15719 |
3/4✓ Branch 0 taken 78 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 112 times.
✓ Branch 3 taken 57 times.
|
169 | for (const Alter_drop *drop : alter_info->drop_list) { |
| 15720 | /* Names of foreign keys in InnoDB are case-insensitive. */ | ||
| 15721 |
4/4✓ Branch 0 taken 24 times.
✓ Branch 1 taken 88 times.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 91 times.
|
136 | if ((drop->type == Alter_drop::FOREIGN_KEY) && |
| 15722 |
4/6✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 21 times.
✓ Branch 5 taken 3 times.
|
24 | (my_strcasecmp(system_charset_info, fk->name().c_str(), drop->name) == |
| 15723 | 0)) { | ||
| 15724 | 21 | is_dropped = true; | |
| 15725 | 21 | break; | |
| 15726 | } | ||
| 15727 | } | ||
| 15728 |
2/2✓ Branch 0 taken 21 times.
✓ Branch 1 taken 57 times.
|
78 | if (is_dropped) continue; |
| 15729 | |||
| 15730 | enum fk_column_change_type changes; | ||
| 15731 | const char *bad_column_name; | ||
| 15732 | |||
| 15733 | 61 | auto fk_columns_lambda = [fk](uint i) { | |
| 15734 | 61 | return fk->elements()[i]->column().name().c_str(); | |
| 15735 | 57 | }; | |
| 15736 |
2/4✓ Branch 0 taken 57 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 57 times.
✗ Branch 3 not taken.
|
57 | changes = fk_check_column_changes(thd, alter_info, fk->elements().size(), |
| 15737 | fk_columns_lambda, &bad_column_name); | ||
| 15738 | |||
| 15739 |
2/5✓ Branch 0 taken 55 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
57 | switch (changes) { |
| 15740 | 55 | case fk_column_change_type::NO_CHANGE: | |
| 15741 | /* No significant changes. We can proceed with ALTER! */ | ||
| 15742 | 55 | break; | |
| 15743 | 2 | case fk_column_change_type::SAFE_FOR_PARENT: | |
| 15744 | case fk_column_change_type::DATA_CHANGE: | ||
| 15745 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | my_error(ER_FK_COLUMN_CANNOT_CHANGE, MYF(0), bad_column_name, |
| 15746 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | fk->name().c_str()); |
| 15747 | 2 | return true; | |
| 15748 | ✗ | case fk_column_change_type::RENAMED: | |
| 15749 | ✗ | my_error(ER_ALTER_OPERATION_NOT_SUPPORTED_REASON, MYF(0), | |
| 15750 | "ALGORITHM=COPY", | ||
| 15751 | ER_THD(thd, ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_FK_RENAME), | ||
| 15752 | "ALGORITHM=INPLACE"); | ||
| 15753 | ✗ | return true; | |
| 15754 | ✗ | case fk_column_change_type::DROPPED: | |
| 15755 | /* | ||
| 15756 | Should already have been checked in | ||
| 15757 | transfer_preexisting_foreign_keys(). | ||
| 15758 | */ | ||
| 15759 | ✗ | assert(false); | |
| 15760 | } | ||
| 15761 | } | ||
| 15762 | |||
| 15763 | 19591 | return false; | |
| 15764 | 20744 | } | |
| 15765 | |||
| 15766 | 1832 | bool collect_and_lock_fk_tables_for_rename_table( | |
| 15767 | THD *thd, const char *db, const char *table_name, | ||
| 15768 | const dd::Table *table_def, const char *new_db, const char *new_table_name, | ||
| 15769 | handlerton *hton, Foreign_key_parents_invalidator *fk_invalidator) { | ||
| 15770 |
1/2✓ Branch 0 taken 1832 times.
✗ Branch 1 not taken.
|
1832 | MDL_request_list mdl_requests; |
| 15771 | |||
| 15772 |
1/2✓ Branch 0 taken 1832 times.
✗ Branch 1 not taken.
|
1832 | if (collect_fk_children(thd, db, table_name, hton, MDL_EXCLUSIVE, |
| 15773 | 1832 | &mdl_requests) || | |
| 15774 |
2/4✓ Branch 0 taken 1832 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1832 times.
✗ Branch 3 not taken.
|
1832 | collect_fk_children(thd, new_db, new_table_name, hton, MDL_EXCLUSIVE, |
| 15775 | 1832 | &mdl_requests) || | |
| 15776 |
2/4✓ Branch 0 taken 1832 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1832 times.
✗ Branch 3 not taken.
|
1832 | collect_fk_parents_for_all_fks(thd, table_def, hton, MDL_EXCLUSIVE, |
| 15777 |
2/4✓ Branch 0 taken 1832 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1832 times.
|
3664 | &mdl_requests, fk_invalidator) || |
| 15778 |
2/4✓ Branch 0 taken 1832 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1832 times.
|
1832 | collect_fk_names_for_rename_table(thd, db, table_name, table_def, hton, |
| 15779 | new_db, new_table_name, &mdl_requests)) | ||
| 15780 | ✗ | return true; | |
| 15781 | |||
| 15782 |
3/4✓ Branch 0 taken 36 times.
✓ Branch 1 taken 1796 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1832 times.
|
1868 | if (!mdl_requests.is_empty() && |
| 15783 |
2/4✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 36 times.
|
36 | thd->mdl_context.acquire_locks(&mdl_requests, |
| 15784 | thd->variables.lock_wait_timeout)) | ||
| 15785 | ✗ | return true; | |
| 15786 | |||
| 15787 | 1832 | return false; | |
| 15788 | } | ||
| 15789 | |||
| 15790 | 1832 | bool adjust_adopted_self_ref_fk_for_simple_rename_table( | |
| 15791 | THD *thd, const char *db, const char *table_name, const char *new_db, | ||
| 15792 | const char *new_table_name, handlerton *hton) { | ||
| 15793 |
1/2✓ Branch 0 taken 1832 times.
✗ Branch 1 not taken.
|
1832 | dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client()); |
| 15794 | 1832 | dd::Table *table_def = nullptr; | |
| 15795 | |||
| 15796 |
4/8✓ Branch 0 taken 1832 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1832 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1832 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1832 times.
|
1832 | if (thd->dd_client()->acquire_for_modification(db, table_name, &table_def)) |
| 15797 | ✗ | return true; | |
| 15798 | |||
| 15799 |
3/4✓ Branch 0 taken 1832 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1813 times.
✓ Branch 3 taken 19 times.
|
1832 | if (table_def->foreign_keys()->empty()) return false; |
| 15800 | |||
| 15801 | 19 | bool has_adopted_fk = false; | |
| 15802 |
6/10✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 19 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 26 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 26 times.
✓ Branch 9 taken 19 times.
|
45 | for (dd::Foreign_key *fk : *(table_def->foreign_keys())) { |
| 15803 |
2/4✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
|
26 | if (my_strcasecmp(table_alias_charset, |
| 15804 | fk->referenced_table_schema_name().c_str(), | ||
| 15805 |
3/4✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 24 times.
|
52 | new_db) == 0 && |
| 15806 |
4/6✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 24 times.
|
26 | my_strcasecmp(table_alias_charset, fk->referenced_table_name().c_str(), |
| 15807 | new_table_name) == 0) { | ||
| 15808 | /* | ||
| 15809 | Check that table has a column which is compatible with the foreign key's | ||
| 15810 | referenced column. | ||
| 15811 | */ | ||
| 15812 |
6/10✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 2 times.
|
4 | for (dd::Foreign_key_element *fk_el : *(fk->elements())) { |
| 15813 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
2 | if (check_table_has_col_compatible_with_fk_ref_col(table_def, fk, fk_el, |
| 15814 | hton)) | ||
| 15815 | ✗ | return true; | |
| 15816 | } | ||
| 15817 | |||
| 15818 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
2 | if (prepare_fk_parent_key(hton, table_def, nullptr, nullptr, true, fk)) |
| 15819 | ✗ | return true; | |
| 15820 | |||
| 15821 | 2 | has_adopted_fk = true; | |
| 15822 | } | ||
| 15823 | } | ||
| 15824 | |||
| 15825 |
4/6✓ Branch 0 taken 2 times.
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
|
19 | return (has_adopted_fk && thd->dd_client()->update(table_def)); |
| 15826 | 1832 | } | |
| 15827 | |||
| 15828 | 1771 | bool adjust_fks_for_rename_table(THD *thd, const char *db, | |
| 15829 | const char *table_name, const char *new_db, | ||
| 15830 | const char *new_table_name, handlerton *hton) { | ||
| 15831 | 1771 | const dd::Table *new_table = nullptr; | |
| 15832 | |||
| 15833 |
4/8✓ Branch 0 taken 1771 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1771 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1771 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1771 times.
|
1771 | if (thd->dd_client()->acquire(new_db, new_table_name, &new_table)) |
| 15834 | ✗ | return true; | |
| 15835 | |||
| 15836 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1771 times.
|
1771 | assert(new_table != nullptr); |
| 15837 | |||
| 15838 |
2/4✓ Branch 0 taken 1771 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1771 times.
|
1771 | if (adjust_fk_children_after_parent_rename(thd, db, table_name, hton, new_db, |
| 15839 | new_table_name)) | ||
| 15840 | ✗ | return true; | |
| 15841 | |||
| 15842 |
3/4✓ Branch 0 taken 1771 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 1767 times.
|
1771 | if (adjust_fk_children_after_parent_def_change(thd, new_db, new_table_name, |
| 15843 | hton, new_table, nullptr)) | ||
| 15844 | 4 | return true; | |
| 15845 | |||
| 15846 |
2/4✓ Branch 0 taken 1767 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1767 times.
|
1767 | if (adjust_fk_parents(thd, new_db, new_table_name, true, nullptr)) |
| 15847 | ✗ | return true; | |
| 15848 | |||
| 15849 | 1767 | return false; | |
| 15850 | } | ||
| 15851 | |||
| 15852 | /** | ||
| 15853 | Check if ALTER TABLE in question is a simple ALTER TABLE RENAME or | ||
| 15854 | ALTER TABLE ENABLE/DISABLE KEYS. | ||
| 15855 | |||
| 15856 | @param alter_info Alter_info describing ALTER. | ||
| 15857 | */ | ||
| 15858 | 182267 | static bool is_simple_rename_or_index_change(const Alter_info *alter_info) { | |
| 15859 | 182267 | return (!(alter_info->flags & | |
| 15860 |
2/2✓ Branch 0 taken 4139 times.
✓ Branch 1 taken 178128 times.
|
186406 | ~(Alter_info::ALTER_RENAME | Alter_info::ALTER_KEYS_ONOFF)) && |
| 15861 |
2/2✓ Branch 0 taken 4103 times.
✓ Branch 1 taken 36 times.
|
4139 | alter_info->requested_algorithm != |
| 15862 | 182267 | Alter_info::ALTER_TABLE_ALGORITHM_COPY); | |
| 15863 | } | ||
| 15864 | |||
| 15865 | /** | ||
| 15866 | Rename table and/or turn indexes on/off without touching .FRM | ||
| 15867 | |||
| 15868 | @param thd Thread handler | ||
| 15869 | @param new_schema Target schema. | ||
| 15870 | @param table_list TABLE_LIST for the table to change | ||
| 15871 | @param keys_onoff ENABLE or DISABLE KEYS? | ||
| 15872 | @param alter_ctx ALTER TABLE runtime context. | ||
| 15873 | |||
| 15874 | @return Operation status | ||
| 15875 | @retval false Success | ||
| 15876 | @retval true Failure | ||
| 15877 | */ | ||
| 15878 | 2033 | static bool simple_rename_or_index_change( | |
| 15879 | THD *thd, const dd::Schema &new_schema, TABLE_LIST *table_list, | ||
| 15880 | Alter_info::enum_enable_or_disable keys_onoff, Alter_table_ctx *alter_ctx) { | ||
| 15881 | 2033 | TABLE *table = table_list->table; | |
| 15882 | 2033 | MDL_ticket *mdl_ticket = table->mdl_ticket; | |
| 15883 | 2033 | int error = 0; | |
| 15884 |
1/2✓ Branch 0 taken 2033 times.
✗ Branch 1 not taken.
|
2033 | handlerton *old_db_type = table->s->db_type(); |
| 15885 | 2033 | bool atomic_ddl = (old_db_type->flags & HTON_SUPPORTS_ATOMIC_DDL); | |
| 15886 | 2033 | Foreign_key_parents_invalidator fk_invalidator; | |
| 15887 | |||
| 15888 |
1/2✓ Branch 0 taken 2033 times.
✗ Branch 1 not taken.
|
2033 | DBUG_TRACE; |
| 15889 | |||
| 15890 |
2/2✓ Branch 0 taken 1229 times.
✓ Branch 1 taken 804 times.
|
2033 | if (keys_onoff != Alter_info::LEAVE_AS_IS) { |
| 15891 |
3/4✓ Branch 0 taken 1229 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 1225 times.
|
1229 | if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN)) |
| 15892 | 4 | return true; | |
| 15893 | |||
| 15894 | // It's now safe to take the table level lock. | ||
| 15895 |
2/4✓ Branch 0 taken 1225 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1225 times.
|
1225 | if (lock_tables(thd, table_list, alter_ctx->tables_opened, 0)) return true; |
| 15896 | |||
| 15897 |
2/2✓ Branch 0 taken 618 times.
✓ Branch 1 taken 607 times.
|
1225 | if (keys_onoff == Alter_info::ENABLE) { |
| 15898 |
2/4✓ Branch 0 taken 618 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 618 times.
✗ Branch 3 not taken.
|
618 | DEBUG_SYNC(thd, "alter_table_enable_indexes"); |
| 15899 |
2/6✓ Branch 0 taken 618 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 618 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
618 | DBUG_EXECUTE_IF("sleep_alter_enable_indexes", my_sleep(6000000);); |
| 15900 |
1/2✓ Branch 0 taken 618 times.
✗ Branch 1 not taken.
|
618 | error = table->file->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); |
| 15901 |
1/2✓ Branch 0 taken 607 times.
✗ Branch 1 not taken.
|
607 | } else if (keys_onoff == Alter_info::DISABLE) |
| 15902 |
1/2✓ Branch 0 taken 607 times.
✗ Branch 1 not taken.
|
607 | error = table->file->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); |
| 15903 | |||
| 15904 |
2/2✓ Branch 0 taken 1128 times.
✓ Branch 1 taken 97 times.
|
1225 | if (error == HA_ERR_WRONG_COMMAND) { |
| 15905 |
2/4✓ Branch 0 taken 1128 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1128 times.
✗ Branch 3 not taken.
|
1128 | push_warning_printf(thd, Sql_condition::SL_NOTE, ER_ILLEGAL_HA, |
| 15906 | ER_THD(thd, ER_ILLEGAL_HA), table->alias); | ||
| 15907 | 1128 | error = 0; | |
| 15908 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 97 times.
|
97 | } else if (error > 0) { |
| 15909 | ✗ | table->file->print_error(error, MYF(0)); | |
| 15910 | ✗ | error = -1; | |
| 15911 | } else { | ||
| 15912 | /** | ||
| 15913 | Update mysql.tables.options with keys_disabled=1/0 based on keys_onoff. | ||
| 15914 | This will used by INFORMATION_SCHEMA.STATISTICS system view to display | ||
| 15915 | keys were disabled. | ||
| 15916 | */ | ||
| 15917 | 97 | dd::Table *tab_obj = nullptr; | |
| 15918 | |||
| 15919 |
4/8✓ Branch 0 taken 97 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 97 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 97 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 97 times.
|
97 | if (thd->dd_client()->acquire_for_modification( |
| 15920 | table_list->db, table_list->table_name, &tab_obj)) | ||
| 15921 | ✗ | error = -1; | |
| 15922 | else { | ||
| 15923 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 97 times.
|
97 | assert(tab_obj != nullptr); |
| 15924 | |||
| 15925 |
5/8✓ Branch 0 taken 97 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 47 times.
✓ Branch 3 taken 50 times.
✓ Branch 4 taken 97 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 97 times.
✗ Branch 7 not taken.
|
97 | tab_obj->options().set("keys_disabled", |
| 15926 | (keys_onoff == Alter_info::DISABLE ? 1 : 0)); | ||
| 15927 | |||
| 15928 | // Update the changes | ||
| 15929 |
1/2✓ Branch 0 taken 97 times.
✗ Branch 1 not taken.
|
97 | bool result = thd->dd_client()->update(tab_obj); |
| 15930 |
2/4✓ Branch 0 taken 97 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 97 times.
✗ Branch 3 not taken.
|
97 | if (!atomic_ddl) result = trans_intermediate_ddl_commit(thd, result); |
| 15931 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 97 times.
|
97 | if (result) error = -1; |
| 15932 | } | ||
| 15933 | } | ||
| 15934 | } | ||
| 15935 | |||
| 15936 |
5/6✓ Branch 0 taken 2029 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 771 times.
✓ Branch 3 taken 1258 times.
✓ Branch 4 taken 771 times.
✓ Branch 5 taken 1258 times.
|
2029 | if (!error && alter_ctx->is_table_renamed()) { |
| 15937 |
1/2✓ Branch 0 taken 771 times.
✗ Branch 1 not taken.
|
771 | THD_STAGE_INFO(thd, stage_rename); |
| 15938 | /* | ||
| 15939 | Then do a 'simple' rename of the table. First we need to close all | ||
| 15940 | instances of 'source' table. | ||
| 15941 | Note that if wait_while_table_is_used() returns error here (i.e. if | ||
| 15942 | this thread was killed) then it must be that previous step of | ||
| 15943 | simple rename did nothing and therefore we can safely return | ||
| 15944 | without additional clean-up. | ||
| 15945 | */ | ||
| 15946 |
3/4✓ Branch 0 taken 771 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 766 times.
|
771 | if (wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN)) |
| 15947 | 21 | return true; | |
| 15948 | |||
| 15949 | 766 | const dd::Table *table_def = nullptr; | |
| 15950 |
4/8✓ Branch 0 taken 766 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 766 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 766 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 766 times.
|
766 | if (thd->dd_client()->acquire(table_list->db, table_list->table_name, |
| 15951 | &table_def)) | ||
| 15952 | ✗ | return true; | |
| 15953 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 766 times.
|
766 | assert(table_def != nullptr); |
| 15954 | |||
| 15955 | /* | ||
| 15956 | Check table encryption privilege, if rename changes database. | ||
| 15957 | */ | ||
| 15958 |
2/2✓ Branch 0 taken 139 times.
✓ Branch 1 taken 627 times.
|
766 | if (alter_ctx->is_database_changed()) { |
| 15959 | 139 | bool is_general_tablespace{false}; | |
| 15960 | 139 | bool is_table_encrypted{false}; | |
| 15961 | dd::Encrypt_result result = | ||
| 15962 |
1/2✓ Branch 0 taken 139 times.
✗ Branch 1 not taken.
|
139 | dd::is_tablespace_encrypted(thd, *table_def, &is_general_tablespace); |
| 15963 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 139 times.
|
139 | if (result.error) { |
| 15964 | 16 | return true; | |
| 15965 | } | ||
| 15966 | 139 | is_table_encrypted = result.value; | |
| 15967 | // If implicit tablespace, read the encryption clause value. | ||
| 15968 |
2/2✓ Branch 0 taken 107 times.
✓ Branch 1 taken 32 times.
|
246 | if (!is_general_tablespace && |
| 15969 |
9/14✓ Branch 0 taken 107 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 107 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 107 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 106 times.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 107 times.
✓ Branch 9 taken 32 times.
✓ Branch 10 taken 106 times.
✓ Branch 11 taken 33 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
|
246 | table_def->options().exists("encrypt_type")) { |
| 15970 | 106 | dd::String_type et; | |
| 15971 |
3/6✓ Branch 0 taken 106 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 106 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 106 times.
✗ Branch 5 not taken.
|
106 | (void)table_def->options().get("encrypt_type", &et); |
| 15972 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 106 times.
|
106 | assert(et.empty() == false); |
| 15973 |
1/2✓ Branch 0 taken 106 times.
✗ Branch 1 not taken.
|
106 | is_table_encrypted = is_encrypted(et); |
| 15974 | 106 | } | |
| 15975 | |||
| 15976 | // If table encryption differ from schema encryption, check privilege. | ||
| 15977 |
3/4✓ Branch 0 taken 139 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 64 times.
✓ Branch 3 taken 75 times.
|
139 | if (new_schema.default_encryption() != is_table_encrypted) { |
| 15978 |
2/2✓ Branch 0 taken 48 times.
✓ Branch 1 taken 16 times.
|
64 | if (opt_table_encryption_privilege_check) { |
| 15979 |
3/4✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 32 times.
|
48 | if (check_table_encryption_admin_access(thd)) { |
| 15980 |
1/2✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
|
16 | my_error(ER_CANNOT_SET_TABLE_ENCRYPTION, MYF(0)); |
| 15981 | 16 | return true; | |
| 15982 | } | ||
| 15983 |
6/8✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 8 times.
✓ Branch 7 taken 8 times.
|
16 | } else if (new_schema.default_encryption() && !is_table_encrypted) { |
| 15984 |
2/4✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
|
8 | push_warning(thd, Sql_condition::SL_WARNING, |
| 15985 | WARN_UNENCRYPTED_TABLE_IN_ENCRYPTED_DB, | ||
| 15986 | ER_THD(thd, WARN_UNENCRYPTED_TABLE_IN_ENCRYPTED_DB)); | ||
| 15987 | } | ||
| 15988 | } | ||
| 15989 | } | ||
| 15990 | |||
| 15991 |
3/4✓ Branch 0 taken 723 times.
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 750 times.
|
1473 | if ((old_db_type->flags & HTON_SUPPORTS_FOREIGN_KEYS) && |
| 15992 |
2/4✓ Branch 0 taken 723 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 723 times.
|
723 | collect_and_lock_fk_tables_for_rename_table( |
| 15993 | thd, table_list->db, table_list->table_name, table_def, | ||
| 15994 | alter_ctx->new_db, alter_ctx->new_alias, old_db_type, | ||
| 15995 | &fk_invalidator)) { | ||
| 15996 | ✗ | return true; | |
| 15997 | } | ||
| 15998 | |||
| 15999 |
2/4✓ Branch 0 taken 750 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 750 times.
|
750 | if (lock_check_constraint_names_for_rename( |
| 16000 | thd, table_list->db, table_list->table_name, table_def, | ||
| 16001 | alter_ctx->new_db, alter_ctx->new_alias)) | ||
| 16002 | ✗ | return true; | |
| 16003 | |||
| 16004 |
1/2✓ Branch 0 taken 750 times.
✗ Branch 1 not taken.
|
750 | close_all_tables_for_name(thd, table->s, false, nullptr); |
| 16005 | |||
| 16006 | /* | ||
| 16007 | Orphan non-self-referencing foreign keys may become non-orphan/adopted | ||
| 16008 | self-referencing foreign keys. Check that table has compatible referenced | ||
| 16009 | column and parent key for such foreign key. Also, update | ||
| 16010 | DD.UNIQUE_CONSTRAINT_NAME. | ||
| 16011 | */ | ||
| 16012 |
3/4✓ Branch 0 taken 723 times.
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 750 times.
|
1473 | if ((old_db_type->flags & HTON_SUPPORTS_FOREIGN_KEYS) && |
| 16013 |
2/4✓ Branch 0 taken 723 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 723 times.
|
723 | adjust_adopted_self_ref_fk_for_simple_rename_table( |
| 16014 | thd, table_list->db, table_list->table_name, alter_ctx->new_db, | ||
| 16015 | alter_ctx->new_alias, old_db_type)) | ||
| 16016 | ✗ | error = -1; | |
| 16017 | |||
| 16018 |
1/2✓ Branch 0 taken 750 times.
✗ Branch 1 not taken.
|
750 | if (!error) { |
| 16019 |
5/6✓ Branch 0 taken 723 times.
✓ Branch 1 taken 27 times.
✓ Branch 2 taken 750 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
✓ Branch 5 taken 740 times.
|
750 | if (mysql_rename_table(thd, old_db_type, alter_ctx->db, |
| 16020 | alter_ctx->table_name, alter_ctx->db, | ||
| 16021 | alter_ctx->table_name, new_schema, | ||
| 16022 | alter_ctx->new_db, alter_ctx->new_alias, | ||
| 16023 | (atomic_ddl ? NO_DD_COMMIT : 0))) | ||
| 16024 | 10 | error = -1; | |
| 16025 |
2/2✓ Branch 0 taken 713 times.
✓ Branch 1 taken 27 times.
|
740 | else if (old_db_type->flags & HTON_SUPPORTS_FOREIGN_KEYS) { |
| 16026 | /* | ||
| 16027 | We don't have SEs which support FKs and don't support atomic DDL. | ||
| 16028 | If we ever to support such engines we need to decide how to handle | ||
| 16029 | errors in the below code for them. | ||
| 16030 | */ | ||
| 16031 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 713 times.
|
713 | assert(atomic_ddl); |
| 16032 | |||
| 16033 |
3/4✓ Branch 0 taken 713 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 712 times.
|
713 | if (adjust_fks_for_rename_table( |
| 16034 | thd, table_list->db, table_list->table_name, alter_ctx->new_db, | ||
| 16035 | alter_ctx->new_alias, old_db_type)) | ||
| 16036 | 1 | error = -1; | |
| 16037 | } | ||
| 16038 | } | ||
| 16039 | } | ||
| 16040 | |||
| 16041 |
2/2✓ Branch 0 taken 1997 times.
✓ Branch 1 taken 11 times.
|
2008 | if (!error) { |
| 16042 | error = | ||
| 16043 |
3/6✓ Branch 0 taken 1997 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1997 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1997 times.
✗ Branch 5 not taken.
|
1997 | write_bin_log(thd, true, thd->query().str, thd->query().length, |
| 16044 |
6/6✓ Branch 0 taken 1795 times.
✓ Branch 1 taken 202 times.
✓ Branch 2 taken 745 times.
✓ Branch 3 taken 1050 times.
✓ Branch 4 taken 712 times.
✓ Branch 5 taken 33 times.
|
2742 | atomic_ddl && (keys_onoff != Alter_info::LEAVE_AS_IS || |
| 16045 | 745 | alter_ctx->is_table_renamed())); | |
| 16046 | |||
| 16047 | // Update referencing views metadata. | ||
| 16048 |
2/2✓ Branch 0 taken 1995 times.
✓ Branch 1 taken 2 times.
|
1997 | if (!error) { |
| 16049 |
1/2✓ Branch 0 taken 1995 times.
✗ Branch 1 not taken.
|
1995 | Uncommitted_tables_guard uncommitted_tables(thd); |
| 16050 | |||
| 16051 | 3990 | error = update_referencing_views_metadata( | |
| 16052 |
1/2✓ Branch 0 taken 1995 times.
✗ Branch 1 not taken.
|
1995 | thd, table_list, alter_ctx->new_db, alter_ctx->new_alias, !atomic_ddl, |
| 16053 | &uncommitted_tables); | ||
| 16054 | |||
| 16055 |
2/2✓ Branch 0 taken 737 times.
✓ Branch 1 taken 1258 times.
|
1995 | if (alter_ctx->is_table_renamed()) { |
| 16056 |
1/2✓ Branch 0 taken 737 times.
✗ Branch 1 not taken.
|
737 | uncommitted_tables.add_table(table_list); |
| 16057 |
1/2✓ Branch 0 taken 737 times.
✗ Branch 1 not taken.
|
737 | tdc_remove_table(thd, TDC_RT_REMOVE_ALL, alter_ctx->new_db, |
| 16058 | alter_ctx->new_name, false); | ||
| 16059 | } | ||
| 16060 | 1995 | } | |
| 16061 | |||
| 16062 | /* | ||
| 16063 | Commit changes to data-dictionary, SE and binary log if it was not done | ||
| 16064 | earlier. We need to do this before releasing/downgrading MDL. | ||
| 16065 | */ | ||
| 16066 |
4/4✓ Branch 0 taken 1995 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1794 times.
✓ Branch 3 taken 201 times.
|
1997 | if (!error && atomic_ddl) |
| 16067 |
4/8✓ Branch 0 taken 1794 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1794 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1785 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1785 times.
|
1794 | error = (trans_commit_stmt(thd) || trans_commit_implicit(thd)); |
| 16068 | |||
| 16069 |
3/4✓ Branch 0 taken 1986 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1986 times.
✗ Branch 3 not taken.
|
1988 | if (!error) fk_invalidator.invalidate(thd); |
| 16070 | } | ||
| 16071 | |||
| 16072 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1986 times.
|
1999 | if (error) { |
| 16073 | /* | ||
| 16074 | We need rollback possible changes to data-dictionary before releasing | ||
| 16075 | or downgrading metadata lock. | ||
| 16076 | |||
| 16077 | Full rollback will synchronize state of data-dictionary in | ||
| 16078 | cache and on disk. Also it is needed in case we have | ||
| 16079 | THD::transaction_rollback_request. | ||
| 16080 | */ | ||
| 16081 |
1/2✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
|
13 | trans_rollback_stmt(thd); |
| 16082 |
1/2✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
|
13 | trans_rollback(thd); |
| 16083 | } | ||
| 16084 | |||
| 16085 |
4/6✓ Branch 0 taken 1797 times.
✓ Branch 1 taken 202 times.
✓ Branch 2 taken 1797 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1797 times.
✗ Branch 5 not taken.
|
1999 | if (atomic_ddl && old_db_type->post_ddl) old_db_type->post_ddl(thd); |
| 16086 | |||
| 16087 |
2/2✓ Branch 0 taken 1986 times.
✓ Branch 1 taken 13 times.
|
1999 | if (!error) { |
| 16088 |
2/2✓ Branch 0 taken 728 times.
✓ Branch 1 taken 1258 times.
|
1986 | if (alter_ctx->is_table_renamed()) |
| 16089 |
1/2✓ Branch 0 taken 728 times.
✗ Branch 1 not taken.
|
728 | thd->locked_tables_list.rename_locked_table( |
| 16090 | table_list, alter_ctx->new_db, alter_ctx->new_name, | ||
| 16091 | alter_ctx->target_mdl_request.ticket); | ||
| 16092 | } else { | ||
| 16093 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 12 times.
|
13 | if (atomic_ddl) { |
| 16094 | /* | ||
| 16095 | Engines that support atomic DDL restore status-quo on error. | ||
| 16096 | So we can safely try to reopen table under old name. | ||
| 16097 | */ | ||
| 16098 | } else { | ||
| 16099 | /* | ||
| 16100 | For engines which don't support atomic DDL we simply close | ||
| 16101 | the table and later downgrade/release metadata lock, as we | ||
| 16102 | don't track at which step error has occurred exactly. | ||
| 16103 | |||
| 16104 | Since such engines do not support FKs downgrading/releasing | ||
| 16105 | the metadata locks should not cause problems with violating | ||
| 16106 | FK invariants for LOCK TABLES. For the same reason, the below | ||
| 16107 | call won't unlink any parent tables which might have been | ||
| 16108 | closed by FK invalidator. | ||
| 16109 | */ | ||
| 16110 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | assert(!(old_db_type->flags & HTON_SUPPORTS_FOREIGN_KEYS)); |
| 16111 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | thd->locked_tables_list.unlink_all_closed_tables(thd, nullptr, 0); |
| 16112 | } | ||
| 16113 | } | ||
| 16114 | |||
| 16115 |
1/2✓ Branch 0 taken 1999 times.
✗ Branch 1 not taken.
|
1999 | bool reopen_error = thd->locked_tables_list.reopen_tables(thd); |
| 16116 | |||
| 16117 |
4/6✓ Branch 0 taken 1986 times.
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 1986 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1986 times.
✗ Branch 5 not taken.
|
1999 | if (!error && !reopen_error) my_ok(thd); |
| 16118 | |||
| 16119 |
2/2✓ Branch 0 taken 894 times.
✓ Branch 1 taken 1105 times.
|
1999 | if ((thd->locked_tables_mode == LTM_LOCK_TABLES || |
| 16120 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 894 times.
|
894 | thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES)) { |
| 16121 | /* | ||
| 16122 | Under LOCK TABLES we should adjust meta-data locks before finishing | ||
| 16123 | statement. Otherwise we can rely on them being released | ||
| 16124 | along with the implicit commit. | ||
| 16125 | */ | ||
| 16126 |
6/6✓ Branch 0 taken 1103 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 1094 times.
✓ Branch 4 taken 9 times.
✓ Branch 5 taken 1096 times.
|
1105 | if (!error && alter_ctx->is_table_renamed()) { |
| 16127 | /* | ||
| 16128 | Note that we ignore reopen_error value here as not keeping target | ||
| 16129 | metadata locks in this case can lead to breaking foreign key | ||
| 16130 | invariants for LOCK TABLES. | ||
| 16131 | */ | ||
| 16132 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
9 | thd->mdl_context.release_all_locks_for_name(mdl_ticket); |
| 16133 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
9 | thd->mdl_context.set_lock_duration(alter_ctx->target_mdl_request.ticket, |
| 16134 | MDL_EXPLICIT); | ||
| 16135 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
9 | alter_ctx->target_mdl_request.ticket->downgrade_lock( |
| 16136 | MDL_SHARED_NO_READ_WRITE); | ||
| 16137 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 8 times.
|
9 | if (alter_ctx->is_database_changed()) |
| 16138 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | thd->mdl_context.set_lock_duration( |
| 16139 | alter_ctx->target_db_mdl_request.ticket, MDL_EXPLICIT); | ||
| 16140 | } else | ||
| 16141 |
1/2✓ Branch 0 taken 1096 times.
✗ Branch 1 not taken.
|
1096 | mdl_ticket->downgrade_lock(MDL_SHARED_NO_READ_WRITE); |
| 16142 | } | ||
| 16143 |
3/4✓ Branch 0 taken 1986 times.
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1986 times.
|
1999 | return error != 0 || reopen_error; |
| 16144 | 2024 | } | |
| 16145 | |||
| 16146 | /* | ||
| 16147 | Temporarily remove secondary keys previously stored in | ||
| 16148 | alter_info->delayed_key_info. | ||
| 16149 | */ | ||
| 16150 | 5 | static bool remove_secondary_keys( | |
| 16151 | THD *thd, HA_CREATE_INFO *create_info, TABLE *table, Alter_info *alter_info, | ||
| 16152 | const dd::Table *table_def, dd::Table *altered_table_def, | ||
| 16153 | std::vector<dd::Index *> *dd_disabled_sec_keys) { | ||
| 16154 | uint i; | ||
| 16155 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | DBUG_TRACE; |
| 16156 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 | assert(alter_info->delayed_key_count > 0); |
| 16157 | |||
| 16158 | /* | ||
| 16159 | We need to mark all fields for read and write as being done in | ||
| 16160 | mysql_alter_table. | ||
| 16161 | */ | ||
| 16162 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | table->use_all_columns(); |
| 16163 | |||
| 16164 | /* | ||
| 16165 | Create Alter_info for the table and fill create_list with fields | ||
| 16166 | definitions. Note that fields not changed, so we set field==orig_field. | ||
| 16167 | */ | ||
| 16168 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | Alter_info alter_info_new(thd->mem_root); |
| 16169 | Field **f_ptr, *field; | ||
| 16170 | |||
| 16171 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
|
15 | for (f_ptr = table->field; (field = *f_ptr); f_ptr++) { |
| 16172 |
2/4✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
|
10 | Create_field *new_field = new (thd->mem_root) Create_field(field, field); |
| 16173 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | alter_info_new.create_list.push_back(new_field); |
| 16174 | } | ||
| 16175 | |||
| 16176 | /* table->key_info cannot be passed to ha_alter_info constructor, | ||
| 16177 | because it has 1-based fieldnr in key_parts while ha_alter_info | ||
| 16178 | expect them to be 0-based */ | ||
| 16179 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | KEY *key_buf = (KEY *)thd->alloc(sizeof(KEY) * table->s->keys); |
| 16180 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 5 times.
|
13 | for (uint key_idx = 0; key_idx < table->s->keys; key_idx++) { |
| 16181 | 8 | KEY *key = table->key_info + key_idx; | |
| 16182 | 16 | KEY_PART_INFO *key_parts_buf = (KEY_PART_INFO *)thd->alloc( | |
| 16183 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | sizeof(KEY_PART_INFO) * key->user_defined_key_parts); |
| 16184 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
|
16 | for (uint key_part_idx = 0; key_part_idx < key->user_defined_key_parts; |
| 16185 | key_part_idx++) { | ||
| 16186 | 8 | key_parts_buf[key_part_idx] = key->key_part[key_part_idx]; | |
| 16187 | 8 | key_parts_buf[key_part_idx].fieldnr--; | |
| 16188 | } | ||
| 16189 | 8 | key_buf[key_idx] = *key; | |
| 16190 | 8 | key_buf[key_idx].key_part = key_parts_buf; | |
| 16191 | } | ||
| 16192 | |||
| 16193 | Alter_inplace_info ha_alter_info(create_info, &alter_info_new, false, key_buf, | ||
| 16194 | 5 | table->s->keys, thd->work_part_info); | |
| 16195 | |||
| 16196 | 5 | ha_alter_info.handler_flags = Alter_inplace_info::DROP_INDEX; | |
| 16197 | 5 | ha_alter_info.index_drop_count = alter_info->delayed_key_count; | |
| 16198 | |||
| 16199 | /* Fill index_drop_buffer with keys to drop */ | ||
| 16200 | 5 | ha_alter_info.index_drop_buffer = | |
| 16201 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | (KEY **)thd->alloc(sizeof(KEY *) * alter_info->delayed_key_count); |
| 16202 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 5 times.
|
12 | for (i = 0; i < alter_info->delayed_key_count; i++) |
| 16203 | 7 | ha_alter_info.index_drop_buffer[i] = &(alter_info->delayed_key_info[i]); | |
| 16204 | |||
| 16205 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
|
5 | if (table->file->check_if_supported_inplace_alter(table, &ha_alter_info) == |
| 16206 | HA_ALTER_INPLACE_NOT_SUPPORTED) | ||
| 16207 | ✗ | return true; | |
| 16208 | |||
| 16209 |
6/10✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 12 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 12 times.
✓ Branch 9 taken 5 times.
|
17 | for (const auto index : *altered_table_def->indexes()) { |
| 16210 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | const char *dd_index_name = index->name().c_str(); |
| 16211 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 12 times.
|
30 | for (i = 0; i < alter_info->delayed_key_count; i++) { |
| 16212 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 11 times.
|
18 | if (strcmp(alter_info->delayed_key_info[i].name, dd_index_name) == 0) { |
| 16213 |
1/2✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 | dd_disabled_sec_keys->push_back(index); |
| 16214 |
2/4✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
|
7 | assert(index->type() == dd::Index::IT_MULTIPLE); |
| 16215 | 7 | index->set_disabled(true); | |
| 16216 | } | ||
| 16217 | } | ||
| 16218 | } | ||
| 16219 | |||
| 16220 | /* Clone old Table and disable indexes we want to remove | ||
| 16221 | (they are also disabled in altered_table_def) */ | ||
| 16222 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | auto td = std::unique_ptr<dd::Table>(table_def->clone()); |
| 16223 |
6/10✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 9 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 9 times.
✓ Branch 9 taken 5 times.
|
14 | for (const auto index : *td->indexes()) { |
| 16224 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
9 | const char *dd_index_name = index->name().c_str(); |
| 16225 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 9 times.
|
22 | for (i = 0; i < alter_info->delayed_key_count; i++) { |
| 16226 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 9 times.
|
13 | if (strcmp(alter_info->delayed_key_info[i].name, dd_index_name) == 0) { |
| 16227 | 4 | index->set_disabled(true); | |
| 16228 | } | ||
| 16229 | } | ||
| 16230 | } | ||
| 16231 | |||
| 16232 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | if (table->file->ha_prepare_inplace_alter_table(table, &ha_alter_info, |
| 16233 | 5 | table_def, td.get()) || | |
| 16234 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | table->file->ha_inplace_alter_table(table, &ha_alter_info, table_def, |
| 16235 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
|
10 | td.get()) || |
| 16236 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
|
5 | table->file->ha_commit_inplace_alter_table(table, &ha_alter_info, true, |
| 16237 | table_def, td.get())) { | ||
| 16238 | ✗ | table->file->ha_commit_inplace_alter_table(table, &ha_alter_info, false, | |
| 16239 | table_def, td.get()); | ||
| 16240 | ✗ | return true; | |
| 16241 | } | ||
| 16242 | |||
| 16243 | 5 | return false; | |
| 16244 | 5 | } | |
| 16245 | |||
| 16246 | /* | ||
| 16247 | Restore secondary keys previously removed in remove_secondary_keys. | ||
| 16248 | */ | ||
| 16249 | |||
| 16250 | 5 | static bool restore_secondary_keys( | |
| 16251 | THD *thd, HA_CREATE_INFO *create_info, TABLE *table, Alter_info *alter_info, | ||
| 16252 | dd::Table *altered_table_def, | ||
| 16253 | std::vector<dd::Index *> *dd_disabled_sec_keys) { | ||
| 16254 | uint i; | ||
| 16255 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | DBUG_ENTER("restore_secondary_keys"); |
| 16256 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 | assert(alter_info->delayed_key_count > 0); |
| 16257 | |||
| 16258 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | THD_STAGE_INFO(thd, stage_restoring_secondary_keys); |
| 16259 | |||
| 16260 | /* | ||
| 16261 | Create Alter_info for the table and fill create_list with fields | ||
| 16262 | definitions. Not that fields not changed, so we set field==ogrig_field. | ||
| 16263 | */ | ||
| 16264 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | Alter_info alter_info_new(thd->mem_root); |
| 16265 | Field **f_ptr, *field; | ||
| 16266 | |||
| 16267 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
|
15 | for (f_ptr = table->field; (field = *f_ptr); f_ptr++) { |
| 16268 |
2/4✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
|
10 | Create_field *new_field = new (thd->mem_root) Create_field(field, field); |
| 16269 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | alter_info_new.create_list.push_back(new_field); |
| 16270 | } | ||
| 16271 | |||
| 16272 | Alter_inplace_info ha_alter_info(create_info, &alter_info_new, false, | ||
| 16273 | 5 | alter_info->delayed_key_info, table->s->keys, | |
| 16274 | 5 | thd->work_part_info); | |
| 16275 | |||
| 16276 | 5 | ha_alter_info.handler_flags = Alter_inplace_info::ADD_INDEX; | |
| 16277 | 5 | ha_alter_info.index_add_count = alter_info->delayed_key_count; | |
| 16278 | |||
| 16279 | 5 | ha_alter_info.index_add_buffer = | |
| 16280 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | (uint *)thd->alloc(sizeof(uint) * alter_info->delayed_key_count); |
| 16281 | |||
| 16282 | /* Clone current version of table def */ | ||
| 16283 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | auto td = std::unique_ptr<dd::Table>(altered_table_def->clone()); |
| 16284 | |||
| 16285 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 5 times.
|
12 | for (const auto index : *dd_disabled_sec_keys) { |
| 16286 | 7 | index->set_disabled(false); | |
| 16287 | } | ||
| 16288 | |||
| 16289 | /* Fill index_add_buffer with key indexes from key_info_buffer */ | ||
| 16290 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 5 times.
|
12 | for (i = 0; i < alter_info->delayed_key_count; i++) |
| 16291 | 7 | ha_alter_info.index_add_buffer[i] = i; | |
| 16292 | |||
| 16293 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
|
5 | if (table->file->check_if_supported_inplace_alter(table, &ha_alter_info) == |
| 16294 | HA_ALTER_INPLACE_NOT_SUPPORTED) | ||
| 16295 | ✗ | DBUG_RETURN(-1); | |
| 16296 | |||
| 16297 | /* Use previously clonned altered_table_def (the one with disabled keys) | ||
| 16298 | and enable keys */ | ||
| 16299 | |||
| 16300 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
5 | if (table->file->ha_prepare_inplace_alter_table( |
| 16301 | 5 | table, &ha_alter_info, td.get(), altered_table_def) || | |
| 16302 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | table->file->ha_inplace_alter_table(table, &ha_alter_info, td.get(), |
| 16303 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
|
8 | altered_table_def) || |
| 16304 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
|
4 | table->file->ha_commit_inplace_alter_table(table, &ha_alter_info, true, |
| 16305 | 4 | td.get(), altered_table_def)) { | |
| 16306 | ✗ | table->file->ha_commit_inplace_alter_table(table, &ha_alter_info, false, | |
| 16307 | ✗ | td.get(), altered_table_def); | |
| 16308 | ✗ | DBUG_RETURN(true); | |
| 16309 | } | ||
| 16310 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | DBUG_RETURN(false); |
| 16311 | 4 | } | |
| 16312 | |||
| 16313 | /** | ||
| 16314 | Auxiliary class implementing RAII principle for getting permission for/ | ||
| 16315 | notification about finished ALTER TABLE from interested storage engines. | ||
| 16316 | |||
| 16317 | @see handlerton::notify_alter_table for details. | ||
| 16318 | */ | ||
| 16319 | |||
| 16320 | class Alter_table_hton_notification_guard { | ||
| 16321 | public: | ||
| 16322 | 92035 | Alter_table_hton_notification_guard(THD *thd, const MDL_key *key) | |
| 16323 | 92035 | : m_hton_notified(false), m_thd(thd), m_key(*key) {} | |
| 16324 | |||
| 16325 | 90851 | bool notify() { | |
| 16326 |
1/2✓ Branch 0 taken 90851 times.
✗ Branch 1 not taken.
|
90851 | if (!ha_notify_alter_table(m_thd, &m_key, HA_NOTIFY_PRE_EVENT)) { |
| 16327 | 90851 | m_hton_notified = true; | |
| 16328 | 90851 | return false; | |
| 16329 | } | ||
| 16330 | ✗ | my_error(ER_LOCK_REFUSED_BY_ENGINE, MYF(0)); | |
| 16331 | ✗ | return true; | |
| 16332 | } | ||
| 16333 | |||
| 16334 | 91419 | ~Alter_table_hton_notification_guard() { | |
| 16335 |
2/2✓ Branch 0 taken 90236 times.
✓ Branch 1 taken 1183 times.
|
91419 | if (m_hton_notified) |
| 16336 | 90236 | (void)ha_notify_alter_table(m_thd, &m_key, HA_NOTIFY_POST_EVENT); | |
| 16337 | 91419 | } | |
| 16338 | |||
| 16339 | private: | ||
| 16340 | bool m_hton_notified; | ||
| 16341 | THD *m_thd; | ||
| 16342 | const MDL_key m_key; | ||
| 16343 | }; | ||
| 16344 | |||
| 16345 | /** | ||
| 16346 | Check if we are changing the SRID specification on a geometry column that | ||
| 16347 | has a spatial index. If that is the case, reject the change since allowing | ||
| 16348 | geometries with different SRIDs in a spatial index will make the index | ||
| 16349 | useless. | ||
| 16350 | |||
| 16351 | @param alter_info Structure describing the changes to be carried out. | ||
| 16352 | |||
| 16353 | @retval true if all of the geometry columns can be altered/changed as | ||
| 16354 | requested | ||
| 16355 | @retval false if the change is considered invalid | ||
| 16356 | */ | ||
| 16357 | 88255 | static bool is_alter_geometry_column_valid(Alter_info *alter_info) { | |
| 16358 | Create_field *create_field; | ||
| 16359 |
1/2✓ Branch 0 taken 88255 times.
✗ Branch 1 not taken.
|
88255 | List_iterator<Create_field> list_it(alter_info->create_list); |
| 16360 | |||
| 16361 |
2/2✓ Branch 0 taken 966483 times.
✓ Branch 1 taken 88244 times.
|
1054727 | while ((create_field = list_it++)) { |
| 16362 | 1963134 | if (create_field->change != nullptr && | |
| 16363 |
6/6✓ Branch 0 taken 30168 times.
✓ Branch 1 taken 936315 times.
✓ Branch 2 taken 124 times.
✓ Branch 3 taken 30044 times.
✓ Branch 4 taken 99 times.
✓ Branch 5 taken 966384 times.
|
966607 | create_field->sql_type == MYSQL_TYPE_GEOMETRY && |
| 16364 |
3/4✓ Branch 0 taken 124 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 99 times.
✓ Branch 3 taken 25 times.
|
124 | create_field->field->type() == MYSQL_TYPE_GEOMETRY) { |
| 16365 | const Field_geom *geom_field = | ||
| 16366 | 99 | down_cast<const Field_geom *>(create_field->field); | |
| 16367 | 99 | const TABLE_SHARE *share = geom_field->table->s; | |
| 16368 |
2/2✓ Branch 0 taken 59 times.
✓ Branch 1 taken 40 times.
|
99 | if (geom_field->get_srid() != create_field->m_srid) { |
| 16369 | /* | ||
| 16370 | Check if there is a spatial index on this column. If that is the | ||
| 16371 | case, reject the change. | ||
| 16372 | */ | ||
| 16373 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 48 times.
|
59 | for (uint i = 0; i < share->keys; ++i) { |
| 16374 |
2/4✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
|
22 | if (geom_field->key_start.is_set(i) && |
| 16375 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
11 | share->key_info[i].flags & HA_SPATIAL) { |
| 16376 | 11 | my_error(ER_CANNOT_ALTER_SRID_DUE_TO_INDEX, MYF(0), | |
| 16377 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
11 | geom_field->field_name); |
| 16378 | 11 | return false; | |
| 16379 | } | ||
| 16380 | } | ||
| 16381 | } | ||
| 16382 | } | ||
| 16383 | } | ||
| 16384 | 88244 | return true; | |
| 16385 | } | ||
| 16386 | |||
| 16387 | /** | ||
| 16388 | Add MDL requests for exclusive lock on names of the foreign keys to | ||
| 16389 | be dropped by ALTER TABLE operation to the lock requests list. | ||
| 16390 | |||
| 16391 | @param thd Thread context. | ||
| 16392 | @param db Table's database before ALTER TABLE | ||
| 16393 | operation. | ||
| 16394 | @param alter_info Alter_info object with the list of FKs | ||
| 16395 | to be dropped. | ||
| 16396 | @param table_def dd::Table describing the table before | ||
| 16397 | ALTER operation. | ||
| 16398 | @param[in,out] mdl_requests List to which MDL requests are to be added. | ||
| 16399 | |||
| 16400 | @retval operation outcome, false if no error. | ||
| 16401 | */ | ||
| 16402 | |||
| 16403 | 90545 | static bool collect_fk_names_for_dropped_fks(THD *thd, const char *db, | |
| 16404 | const Alter_info *alter_info, | ||
| 16405 | const dd::Table *table_def, | ||
| 16406 | MDL_request_list *mdl_requests) { | ||
| 16407 |
2/2✓ Branch 0 taken 11591 times.
✓ Branch 1 taken 90545 times.
|
102136 | for (const Alter_drop *drop : alter_info->drop_list) { |
| 16408 |
2/2✓ Branch 0 taken 64 times.
✓ Branch 1 taken 11527 times.
|
11591 | if (drop->type == Alter_drop::FOREIGN_KEY) { |
| 16409 |
6/10✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 64 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 64 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 71 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 71 times.
✓ Branch 9 taken 13 times.
|
84 | for (const dd::Foreign_key *fk : table_def->foreign_keys()) { |
| 16410 |
2/4✓ Branch 0 taken 71 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 71 times.
✗ Branch 3 not taken.
|
71 | if (my_strcasecmp(system_charset_info, drop->name, |
| 16411 |
2/2✓ Branch 0 taken 51 times.
✓ Branch 1 taken 20 times.
|
71 | fk->name().c_str()) == 0) { |
| 16412 | /* | ||
| 16413 | Since foreign key names are case-insensitive we need to lowercase | ||
| 16414 | them before passing to MDL subsystem. | ||
| 16415 | */ | ||
| 16416 | char fk_name[NAME_LEN + 1]; | ||
| 16417 |
2/4✓ Branch 0 taken 51 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 51 times.
✗ Branch 3 not taken.
|
51 | strmake(fk_name, fk->name().c_str(), NAME_LEN); |
| 16418 |
1/2✓ Branch 0 taken 51 times.
✗ Branch 1 not taken.
|
51 | my_casedn_str(system_charset_info, fk_name); |
| 16419 | |||
| 16420 |
1/2✓ Branch 0 taken 51 times.
✗ Branch 1 not taken.
|
51 | MDL_request *mdl_request = new (thd->mem_root) MDL_request; |
| 16421 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 51 times.
|
51 | if (mdl_request == nullptr) return true; |
| 16422 | |||
| 16423 |
1/2✓ Branch 0 taken 51 times.
✗ Branch 1 not taken.
|
51 | MDL_REQUEST_INIT(mdl_request, MDL_key::FOREIGN_KEY, db, fk_name, |
| 16424 | MDL_EXCLUSIVE, MDL_STATEMENT); | ||
| 16425 | |||
| 16426 |
1/2✓ Branch 0 taken 51 times.
✗ Branch 1 not taken.
|
51 | mdl_requests->push_front(mdl_request); |
| 16427 | 51 | break; | |
| 16428 | } | ||
| 16429 | } | ||
| 16430 | } | ||
| 16431 | } | ||
| 16432 | 90545 | return false; | |
| 16433 | } | ||
| 16434 | |||
| 16435 | /** | ||
| 16436 | This function will check if we are dropping a functional index. In that | ||
| 16437 | case, the function will add any related hidden generated columns to the drop | ||
| 16438 | list as well. | ||
| 16439 | |||
| 16440 | @param thd Thread handler | ||
| 16441 | @param alter_info The changes to be carried out | ||
| 16442 | @param table_list The current table reference | ||
| 16443 | |||
| 16444 | @retval true on error (my_error is already called) | ||
| 16445 | @retval false on success | ||
| 16446 | */ | ||
| 16447 | 91870 | static bool handle_drop_functional_index(THD *thd, Alter_info *alter_info, | |
| 16448 | TABLE_LIST *table_list) { | ||
| 16449 | // Check if we are dropping a functional index. In that case, we need to drop | ||
| 16450 | // the source column as well. | ||
| 16451 |
2/2✓ Branch 0 taken 12062 times.
✓ Branch 1 taken 91869 times.
|
103931 | for (const Alter_drop *drop : alter_info->drop_list) { |
| 16452 |
2/2✓ Branch 0 taken 8793 times.
✓ Branch 1 taken 3269 times.
|
12062 | if (drop->type == Alter_drop::KEY) { |
| 16453 |
2/2✓ Branch 0 taken 16508 times.
✓ Branch 1 taken 8793 times.
|
25301 | for (uint j = 0; j < table_list->table->s->keys; j++) { |
| 16454 | 16508 | const KEY &key_info = table_list->table->s->key_info[j]; | |
| 16455 |
2/2✓ Branch 0 taken 7934 times.
✓ Branch 1 taken 8574 times.
|
16508 | if (my_strcasecmp(system_charset_info, key_info.name, drop->name) == |
| 16456 | 0) { | ||
| 16457 |
2/2✓ Branch 0 taken 12044 times.
✓ Branch 1 taken 7934 times.
|
19978 | for (uint k = 0; k < key_info.user_defined_key_parts; ++k) { |
| 16458 | 12044 | const KEY_PART_INFO &key_part = key_info.key_part[k]; | |
| 16459 |
2/2✓ Branch 0 taken 73 times.
✓ Branch 1 taken 11971 times.
|
12044 | if (key_part.field->is_field_for_functional_index()) { |
| 16460 | // Add column to drop list | ||
| 16461 | Alter_drop *column_drop = new (thd->mem_root) | ||
| 16462 |
1/2✓ Branch 0 taken 73 times.
✗ Branch 1 not taken.
|
73 | Alter_drop(Alter_drop::COLUMN, key_part.field->field_name); |
| 16463 |
1/2✓ Branch 0 taken 73 times.
✗ Branch 1 not taken.
|
73 | alter_info->drop_list.push_back(column_drop); |
| 16464 | 73 | alter_info->flags |= Alter_info::ALTER_DROP_COLUMN; | |
| 16465 | } | ||
| 16466 | } | ||
| 16467 | } | ||
| 16468 | } | ||
| 16469 |
2/2✓ Branch 0 taken 3102 times.
✓ Branch 1 taken 167 times.
|
3269 | } else if (drop->type == Alter_drop::COLUMN) { |
| 16470 |
2/2✓ Branch 0 taken 18992 times.
✓ Branch 1 taken 3101 times.
|
22093 | for (uint j = 0; j < table_list->table->s->fields; j++) { |
| 16471 | 18992 | Field *field = table_list->table->s->field[j]; | |
| 16472 | 18992 | if (my_strcasecmp(system_charset_info, field->field_name, drop->name) == | |
| 16473 |
6/6✓ Branch 0 taken 3093 times.
✓ Branch 1 taken 15899 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 3092 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 18991 times.
|
22085 | 0 && |
| 16474 | 3093 | field->is_field_for_functional_index()) { | |
| 16475 | 1 | my_error(ER_CANNOT_DROP_COLUMN_FUNCTIONAL_INDEX, MYF(0), | |
| 16476 | field->field_name); | ||
| 16477 | 1 | return true; | |
| 16478 | } | ||
| 16479 | } | ||
| 16480 | } | ||
| 16481 | } | ||
| 16482 | |||
| 16483 | 91869 | return false; | |
| 16484 | } | ||
| 16485 | |||
| 16486 | /** | ||
| 16487 | This function will check if we are renaming a functional index. In that case, | ||
| 16488 | the function will add a "change column" operation to the create list that | ||
| 16489 | renames any affected hidden generated column(s). The reason is that the hidden | ||
| 16490 | generated column name is generated by MD5(key name + key part number), so a | ||
| 16491 | change in the index name will change the name of the column. | ||
| 16492 | |||
| 16493 | @param thd thread handler | ||
| 16494 | @param alter_info the changes to be carried out. | ||
| 16495 | @param table_list a reference to the current table | ||
| 16496 | |||
| 16497 | @retval true OOM | ||
| 16498 | @retval false success | ||
| 16499 | */ | ||
| 16500 | 215 | static bool handle_rename_functional_index(THD *thd, Alter_info *alter_info, | |
| 16501 | TABLE_LIST *table_list) { | ||
| 16502 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 215 times.
|
215 | assert(alter_info->flags & Alter_info::ALTER_RENAME_INDEX); |
| 16503 | |||
| 16504 | 220 | for (const Alter_rename_key *alter_rename_key : | |
| 16505 |
2/2✓ Branch 0 taken 220 times.
✓ Branch 1 taken 215 times.
|
435 | alter_info->alter_rename_key_list) { |
| 16506 | // Find the matching existing index | ||
| 16507 |
2/2✓ Branch 0 taken 590 times.
✓ Branch 1 taken 47 times.
|
637 | for (uint j = 0; j < table_list->table->s->keys; ++j) { |
| 16508 | 590 | const KEY &key = table_list->table->s->key_info[j]; | |
| 16509 | 590 | if (my_strcasecmp(system_charset_info, key.name, | |
| 16510 |
2/2✓ Branch 0 taken 173 times.
✓ Branch 1 taken 417 times.
|
590 | alter_rename_key->old_name) == 0) { |
| 16511 |
2/2✓ Branch 0 taken 285 times.
✓ Branch 1 taken 173 times.
|
458 | for (uint k = 0; k < key.actual_key_parts; ++k) { |
| 16512 | 285 | const KEY_PART_INFO &key_part = key.key_part[k]; | |
| 16513 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 276 times.
|
285 | if (key_part.field->is_field_for_functional_index()) { |
| 16514 | // Rename the field. But use the field that exists in the table | ||
| 16515 | // object. In particular, the field object in KEY_PART_INFO does | ||
| 16516 | // not have the generated column expression. | ||
| 16517 |
2/2✓ Branch 0 taken 104 times.
✓ Branch 1 taken 9 times.
|
113 | for (uint l = 0; l < table_list->table->s->fields; ++l) { |
| 16518 | 104 | Field *field = table_list->table->field[l]; | |
| 16519 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 95 times.
|
104 | if (field->field_index() == key_part.field->field_index()) { |
| 16520 | Create_field *new_create_field = | ||
| 16521 |
2/4✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
|
9 | new (thd->mem_root) Create_field(field, nullptr); |
| 16522 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
|
9 | if (new_create_field == nullptr) { |
| 16523 | ✗ | return true; /* purecov: deadcode */ | |
| 16524 | } | ||
| 16525 | |||
| 16526 | 9 | new_create_field->change = field->field_name; | |
| 16527 | 9 | new_create_field->after = nullptr; | |
| 16528 | 9 | new_create_field->field_name = | |
| 16529 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
9 | make_functional_index_column_name( |
| 16530 | 9 | alter_rename_key->new_name, k, alter_info->create_list, | |
| 16531 | thd->mem_root); | ||
| 16532 | |||
| 16533 | 9 | alter_info->create_list.push_back(new_create_field); | |
| 16534 | 9 | alter_info->flags |= Alter_info::ALTER_CHANGE_COLUMN; | |
| 16535 | } | ||
| 16536 | } | ||
| 16537 | } | ||
| 16538 | } | ||
| 16539 | |||
| 16540 | 173 | break; | |
| 16541 | } | ||
| 16542 | } | ||
| 16543 | } | ||
| 16544 | |||
| 16545 | 215 | return false; | |
| 16546 | } | ||
| 16547 | |||
| 16548 | class Diagnostics_area_man { | ||
| 16549 | THD *m_thd; | ||
| 16550 | Diagnostics_area *da_prev; | ||
| 16551 | Diagnostics_area da; | ||
| 16552 | |||
| 16553 | public: | ||
| 16554 | ✗ | Diagnostics_area_man(THD *thd) | |
| 16555 | ✗ | : m_thd(thd), da_prev(thd->get_stmt_da()), da(false) { | |
| 16556 | // Don't copy existing conditions from the old DA so we don't get them | ||
| 16557 | // twice when we call copy_non_errors_from_da below. | ||
| 16558 | ✗ | m_thd->push_diagnostics_area(&da, false); | |
| 16559 | } | ||
| 16560 | |||
| 16561 | ✗ | ~Diagnostics_area_man() { | |
| 16562 | ✗ | m_thd->pop_diagnostics_area(); | |
| 16563 | |||
| 16564 | ✗ | if (da.is_error()) { | |
| 16565 | ✗ | da_prev->set_error_status(da.mysql_errno(), da.message_text(), | |
| 16566 | da.returned_sqlstate()); | ||
| 16567 | ✗ | da_prev->push_warning(m_thd, da.mysql_errno(), da.returned_sqlstate(), | |
| 16568 | Sql_condition::SL_ERROR, da.message_text()); | ||
| 16569 | } | ||
| 16570 | } | ||
| 16571 | }; | ||
| 16572 | |||
| 16573 | /** | ||
| 16574 | Alter table | ||
| 16575 | |||
| 16576 | @param thd Thread handle | ||
| 16577 | @param new_db If there is a RENAME clause | ||
| 16578 | @param new_name If there is a RENAME clause | ||
| 16579 | @param create_info Information from the parsing phase about new | ||
| 16580 | table properties. | ||
| 16581 | @param table_list The table to change. | ||
| 16582 | @param alter_info Lists of fields, keys to be changed, added | ||
| 16583 | or dropped. | ||
| 16584 | |||
| 16585 | @retval true Error | ||
| 16586 | @retval false Success | ||
| 16587 | |||
| 16588 | This is a veery long function and is everything but the kitchen sink :) | ||
| 16589 | It is used to alter a table and not only by ALTER TABLE but also | ||
| 16590 | CREATE|DROP INDEX are mapped on this function. | ||
| 16591 | |||
| 16592 | When the ALTER TABLE statement just does a RENAME or ENABLE|DISABLE KEYS, | ||
| 16593 | or both, then this function short cuts its operation by renaming | ||
| 16594 | the table and/or enabling/disabling the keys. In this case, the FRM is | ||
| 16595 | not changed, directly by mysql_alter_table. However, if there is a | ||
| 16596 | RENAME + change of a field, or an index, the short cut is not used. | ||
| 16597 | See how `create_list` is used to generate the new FRM regarding the | ||
| 16598 | structure of the fields. The same is done for the indices of the table. | ||
| 16599 | |||
| 16600 | Altering a table can be done in two ways. The table can be modified | ||
| 16601 | directly using an in-place algorithm, or the changes can be done using | ||
| 16602 | an intermediate temporary table (copy). In-place is the preferred | ||
| 16603 | algorithm as it avoids copying table data. The storage engine | ||
| 16604 | selects which algorithm to use in check_if_supported_inplace_alter() | ||
| 16605 | based on information about the table changes from fill_alter_inplace_info(). | ||
| 16606 | */ | ||
| 16607 | |||
| 16608 | 92067 | bool mysql_alter_table(THD *thd, const char *new_db, const char *new_name, | |
| 16609 | HA_CREATE_INFO *create_info, TABLE_LIST *table_list, | ||
| 16610 | Alter_info *alter_info) { | ||
| 16611 |
1/2✓ Branch 0 taken 92067 times.
✗ Branch 1 not taken.
|
92067 | DBUG_TRACE; |
| 16612 | |||
| 16613 | /* | ||
| 16614 | This change is necessary for MyRocks at | ||
| 16615 | https://github.com/facebook/mysql-5.6/commit/1046d4f7074 | ||
| 16616 | |||
| 16617 | Populate the actual user table name which is getting altered. | ||
| 16618 | This flag will be used to put some additional constraints on user tables.*/ | ||
| 16619 |
6/10✓ Branch 0 taken 92067 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 92067 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 92067 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 92067 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 50752 times.
✓ Branch 9 taken 41315 times.
|
92067 | if (!dd::get_dictionary()->is_system_table_name(table_list->db, |
| 16620 | table_list->table_name)) { | ||
| 16621 |
1/2✓ Branch 0 taken 50752 times.
✗ Branch 1 not taken.
|
50752 | create_info->actual_user_table_name = table_list->table_name; |
| 16622 | } | ||
| 16623 | /* | ||
| 16624 | Check if we attempt to alter mysql.slow_log or | ||
| 16625 | mysql.general_log table and return an error if | ||
| 16626 | it is the case. | ||
| 16627 | TODO: this design is obsolete and will be removed. | ||
| 16628 | */ | ||
| 16629 | enum_log_table_type table_kind = | ||
| 16630 |
1/2✓ Branch 0 taken 92067 times.
✗ Branch 1 not taken.
|
92067 | query_logger.check_if_log_table(table_list, false); |
| 16631 | |||
| 16632 |
2/2✓ Branch 0 taken 1001 times.
✓ Branch 1 taken 91066 times.
|
92067 | if (table_kind != QUERY_LOG_NONE) { |
| 16633 | /* Disable alter of enabled query log tables */ | ||
| 16634 |
3/4✓ Branch 0 taken 1001 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 998 times.
|
1001 | if (query_logger.is_log_table_enabled(table_kind)) { |
| 16635 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | my_error(ER_BAD_LOG_STATEMENT, MYF(0), "ALTER"); |
| 16636 | 3 | return true; | |
| 16637 | } | ||
| 16638 | |||
| 16639 | /* Disable alter of log tables to unsupported engine */ | ||
| 16640 |
2/2✓ Branch 0 taken 207 times.
✓ Branch 1 taken 791 times.
|
998 | if ((create_info->used_fields & HA_CREATE_USED_ENGINE) && |
| 16641 |
1/2✓ Branch 0 taken 207 times.
✗ Branch 1 not taken.
|
207 | (!create_info->db_type || /* unknown engine */ |
| 16642 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 206 times.
|
207 | !(create_info->db_type->flags & HTON_SUPPORT_LOG_TABLES))) { |
| 16643 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_UNSUPORTED_LOG_ENGINE, MYF(0)); |
| 16644 | 1 | return true; | |
| 16645 | } | ||
| 16646 | |||
| 16647 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 996 times.
|
997 | if (alter_info->flags & Alter_info::ALTER_PARTITION) { |
| 16648 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_WRONG_USAGE, MYF(0), "PARTITION", "log table"); |
| 16649 | 1 | return true; | |
| 16650 | } | ||
| 16651 | } | ||
| 16652 | |||
| 16653 | // Reject request to ALTER TABLE with START TRANSACTION. | ||
| 16654 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 92061 times.
|
92062 | if (create_info->m_transactional_ddl) { |
| 16655 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_NOT_ALLOWED_WITH_START_TRANSACTION, MYF(0), |
| 16656 | "with ALTER TABLE command."); | ||
| 16657 | 1 | return true; | |
| 16658 | } | ||
| 16659 | |||
| 16660 |
2/2✓ Branch 0 taken 35 times.
✓ Branch 1 taken 92026 times.
|
92061 | if (alter_info->with_validation != Alter_info::ALTER_VALIDATION_DEFAULT && |
| 16661 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 30 times.
|
35 | !(alter_info->flags & |
| 16662 | (Alter_info::ALTER_ADD_COLUMN | Alter_info::ALTER_CHANGE_COLUMN))) { | ||
| 16663 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | my_error(ER_WRONG_USAGE, MYF(0), "ALTER", "WITH VALIDATION"); |
| 16664 | 5 | return true; | |
| 16665 | } | ||
| 16666 | |||
| 16667 |
2/2✓ Branch 0 taken 18993 times.
✓ Branch 1 taken 73063 times.
|
92056 | if ((alter_info->flags & Alter_info::ALTER_ADD_COLUMN) == |
| 16668 | Alter_info::ALTER_ADD_COLUMN) { | ||
| 16669 |
6/10✓ Branch 0 taken 18993 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18993 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 31080 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 50065 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 31080 times.
✓ Branch 9 taken 18985 times.
|
50065 | for (auto create_field : alter_info->create_list) { |
| 16670 |
2/2✓ Branch 0 taken 127 times.
✓ Branch 1 taken 30953 times.
|
31080 | if (create_field.m_default_val_expr) { |
| 16671 | // ALTER TABLE .. DEFAULT (NDF function) should be rejected for mixed or | ||
| 16672 | // row binlog_format. For statement binlog_format it should be allowed | ||
| 16673 | // to continue and warning should be logged and/or pushed to the client | ||
| 16674 |
5/6✓ Branch 0 taken 127 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 119 times.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 119 times.
|
254 | if ((thd->variables.option_bits & OPTION_BIN_LOG) && |
| 16675 | 127 | thd->lex->is_stmt_unsafe( | |
| 16676 | Query_tables_list::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION)) { | ||
| 16677 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
|
8 | if (thd->variables.binlog_format == BINLOG_FORMAT_STMT) { |
| 16678 |
8/16✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 2 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 2 times.
✗ Branch 15 not taken.
|
2 | LogErr(WARNING_LEVEL, ER_SERVER_BINLOG_UNSAFE_SYSTEM_FUNCTION, |
| 16679 | "ALTER TABLE .. DEFAULT (NDF function)"); | ||
| 16680 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | push_warning(thd, Sql_condition::SL_WARNING, |
| 16681 | ER_BINLOG_UNSAFE_SYSTEM_FUNCTION, | ||
| 16682 | ER_THD(thd, ER_BINLOG_UNSAFE_SYSTEM_FUNCTION)); | ||
| 16683 | 2 | break; | |
| 16684 | } else { | ||
| 16685 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | my_error(ER_BINLOG_UNSAFE_SYSTEM_FUNCTION, MYF(0)); |
| 16686 | 6 | return true; | |
| 16687 | } | ||
| 16688 | } | ||
| 16689 | } | ||
| 16690 | } | ||
| 16691 | } | ||
| 16692 | |||
| 16693 | // LOCK clause doesn't make any sense for ALGORITHM=INSTANT. | ||
| 16694 |
2/2✓ Branch 0 taken 1029 times.
✓ Branch 1 taken 91021 times.
|
92050 | if (alter_info->requested_algorithm == |
| 16695 | 1029 | Alter_info::ALTER_TABLE_ALGORITHM_INSTANT && | |
| 16696 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1026 times.
|
1029 | alter_info->requested_lock != Alter_info::ALTER_TABLE_LOCK_DEFAULT) { |
| 16697 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | my_error(ER_WRONG_USAGE, MYF(0), "ALGORITHM=INSTANT", |
| 16698 | "LOCK=NONE/SHARED/EXCLUSIVE"); | ||
| 16699 | 3 | return true; | |
| 16700 | } | ||
| 16701 | |||
| 16702 |
1/2✓ Branch 0 taken 92047 times.
✗ Branch 1 not taken.
|
92047 | THD_STAGE_INFO(thd, stage_init); |
| 16703 | |||
| 16704 | // Reject invalid usage of the 'mysql' tablespace. | ||
| 16705 |
5/8✓ Branch 0 taken 92047 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 92047 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 92047 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 9 times.
✓ Branch 7 taken 92038 times.
|
92047 | if (dd::invalid_tablespace_usage(thd, table_list->db, table_list->table_name, |
| 16706 | create_info)) | ||
| 16707 | 9 | return true; | |
| 16708 | |||
| 16709 | /* | ||
| 16710 | Assign target tablespace name to enable locking in lock_table_names(). | ||
| 16711 | Reject invalid name lengths. Names will be validated after the table is | ||
| 16712 | opened and the SE (needed for SE specific validation) is identified. | ||
| 16713 | */ | ||
| 16714 |
2/2✓ Branch 0 taken 5234 times.
✓ Branch 1 taken 86804 times.
|
92038 | if (create_info->tablespace) { |
| 16715 |
3/4✓ Branch 0 taken 5234 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 5232 times.
|
5234 | if (validate_tablespace_name_length(create_info->tablespace)) return true; |
| 16716 | |||
| 16717 |
2/4✓ Branch 0 taken 5232 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5232 times.
|
5232 | if (lex_string_strmake(thd->mem_root, &table_list->target_tablespace_name, |
| 16718 | create_info->tablespace, | ||
| 16719 | strlen(create_info->tablespace))) { | ||
| 16720 | ✗ | my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATALERROR)); | |
| 16721 | ✗ | return true; | |
| 16722 | } | ||
| 16723 | } | ||
| 16724 | |||
| 16725 | /* Validate that AUTOEXTEND_SIZE option is not specified for | ||
| 16726 | temporary tables */ | ||
| 16727 |
2/2✓ Branch 0 taken 1185 times.
✓ Branch 1 taken 90851 times.
|
92036 | if (is_temporary_table(table_list)) { |
| 16728 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1184 times.
|
1185 | if (create_info->m_implicit_tablespace_autoextend_size > 0) { |
| 16729 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_CANNOT_USE_AUTOEXTEND_SIZE_CLAUSE, MYF(0), "temporary"); |
| 16730 | 1 | return true; | |
| 16731 | } | ||
| 16732 | } | ||
| 16733 | |||
| 16734 | /* | ||
| 16735 | Reject invalid tablespace name lengths specified for partitions. | ||
| 16736 | Names will be validated after the table has been opened. | ||
| 16737 | */ | ||
| 16738 |
2/4✓ Branch 0 taken 92035 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 92035 times.
|
92035 | if (validate_partition_tablespace_name_lengths(thd->lex->part_info)) |
| 16739 | ✗ | return true; | |
| 16740 | |||
| 16741 | /* | ||
| 16742 | Assign the partition info, so that the locks on tablespaces | ||
| 16743 | assigned for any new partitions added would be acquired during | ||
| 16744 | open_table. | ||
| 16745 | */ | ||
| 16746 | 92035 | thd->work_part_info = thd->lex->part_info; | |
| 16747 | |||
| 16748 | /* | ||
| 16749 | Code below can handle only base tables so ensure that we won't open a view. | ||
| 16750 | Note that RENAME TABLE the only ALTER clause which is supported for views | ||
| 16751 | has been already processed. | ||
| 16752 | */ | ||
| 16753 | 92035 | table_list->required_type = dd::enum_table_type::BASE_TABLE; | |
| 16754 | |||
| 16755 | /* | ||
| 16756 | If we are about to ALTER non-temporary table we need to get permission | ||
| 16757 | from/notify interested storage engines. | ||
| 16758 | */ | ||
| 16759 | Alter_table_hton_notification_guard notification_guard( | ||
| 16760 |
1/2✓ Branch 0 taken 92035 times.
✗ Branch 1 not taken.
|
92035 | thd, &table_list->mdl_request.key); |
| 16761 | |||
| 16762 |
5/8✓ Branch 0 taken 90851 times.
✓ Branch 1 taken 1184 times.
✓ Branch 2 taken 90851 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 90851 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 92035 times.
|
92035 | if (!is_temporary_table(table_list) && notification_guard.notify()) |
| 16763 | ✗ | return true; | |
| 16764 | |||
| 16765 | 92035 | Alter_table_prelocking_strategy alter_prelocking_strategy; | |
| 16766 | |||
| 16767 |
3/4✓ Branch 0 taken 89655 times.
✓ Branch 1 taken 2380 times.
✓ Branch 2 taken 89655 times.
✗ Branch 3 not taken.
|
92035 | DEBUG_SYNC(thd, "alter_table_before_open_tables"); |
| 16768 | uint tables_opened; | ||
| 16769 |
1/2✓ Branch 0 taken 92035 times.
✗ Branch 1 not taken.
|
92035 | bool error = open_tables(thd, &table_list, &tables_opened, 0, |
| 16770 | &alter_prelocking_strategy); | ||
| 16771 | |||
| 16772 |
3/4✓ Branch 0 taken 89655 times.
✓ Branch 1 taken 2380 times.
✓ Branch 2 taken 89655 times.
✗ Branch 3 not taken.
|
92035 | DEBUG_SYNC(thd, "alter_opened_table"); |
| 16773 | |||
| 16774 |
2/2✓ Branch 0 taken 165 times.
✓ Branch 1 taken 91870 times.
|
92035 | if (error) return true; |
| 16775 | |||
| 16776 | // If we are removing a functional index, add any related hidden generated | ||
| 16777 | // columns to the drop list as well. | ||
| 16778 |
3/4✓ Branch 0 taken 91870 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 91869 times.
|
91870 | if (handle_drop_functional_index(thd, alter_info, table_list)) { |
| 16779 | 1 | return true; | |
| 16780 | } | ||
| 16781 | |||
| 16782 | // If we are renaming a functional index, rename any related hidden generated | ||
| 16783 | // columns as well. | ||
| 16784 |
2/2✓ Branch 0 taken 215 times.
✓ Branch 1 taken 91654 times.
|
91869 | if (alter_info->flags & Alter_info::ALTER_RENAME_INDEX) { |
| 16785 |
2/4✓ Branch 0 taken 215 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 215 times.
|
215 | if (handle_rename_functional_index(thd, alter_info, table_list)) { |
| 16786 | ✗ | return true; /* purecov: deadcode */ | |
| 16787 | } | ||
| 16788 | } | ||
| 16789 | |||
| 16790 | // Check tablespace name validity for the relevant engine. | ||
| 16791 | { | ||
| 16792 | // If there is no target handlerton, use the current. | ||
| 16793 | 91869 | const handlerton *target_handlerton = create_info->db_type; | |
| 16794 |
2/2✓ Branch 0 taken 87959 times.
✓ Branch 1 taken 3910 times.
|
91869 | if (target_handlerton == nullptr) |
| 16795 | 87959 | target_handlerton = table_list->table->file->ht; | |
| 16796 | |||
| 16797 | /* | ||
| 16798 | Reject invalid tablespace names for the relevant engine, if the ALTER | ||
| 16799 | statement changes either tablespace or engine. We do this after the table | ||
| 16800 | has been opened because we need the handlerton and tablespace information. | ||
| 16801 | No need to validate if neither engine nor tablespace is changed, then the | ||
| 16802 | validation was done when the table was created. | ||
| 16803 | */ | ||
| 16804 |
4/4✓ Branch 0 taken 86641 times.
✓ Branch 1 taken 5228 times.
✓ Branch 2 taken 3900 times.
✓ Branch 3 taken 82741 times.
|
91869 | if (create_info->tablespace || create_info->db_type) { |
| 16805 | // If there is no target table level tablespace, use the current. | ||
| 16806 | 9128 | const char *target_tablespace = create_info->tablespace; | |
| 16807 |
2/2✓ Branch 0 taken 3900 times.
✓ Branch 1 taken 5228 times.
|
9128 | if (target_tablespace == nullptr) |
| 16808 | 3900 | target_tablespace = table_list->table->s->tablespace; | |
| 16809 | |||
| 16810 | // Check the tablespace/engine combination. | ||
| 16811 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9128 times.
|
9128 | assert(target_handlerton); |
| 16812 |
4/4✓ Branch 0 taken 6977 times.
✓ Branch 1 taken 2151 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 9122 times.
|
16105 | if (target_tablespace != nullptr && |
| 16813 |
3/4✓ Branch 0 taken 6977 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 6971 times.
|
6977 | validate_tablespace_name(TS_CMD_NOT_DEFINED, target_tablespace, |
| 16814 | target_handlerton)) | ||
| 16815 | 6 | return true; | |
| 16816 | } | ||
| 16817 | |||
| 16818 | // Reject invalid tablespace names specified for partitions. | ||
| 16819 |
3/4✓ Branch 0 taken 91863 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 91860 times.
|
91863 | if (validate_partition_tablespace_names(thd->lex->part_info, |
| 16820 | target_handlerton)) | ||
| 16821 | 3 | return true; | |
| 16822 | } | ||
| 16823 | |||
| 16824 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 91850 times.
|
91860 | if (validate_secondary_engine_option(*alter_info, *create_info, |
| 16825 |
1/2✓ Branch 0 taken 91860 times.
✗ Branch 1 not taken.
|
91860 | *table_list->table)) |
| 16826 | 10 | return true; | |
| 16827 | |||
| 16828 |
2/4✓ Branch 0 taken 91850 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 91850 times.
|
91850 | if (lock_trigger_names(thd, table_list)) return true; |
| 16829 | |||
| 16830 | /* | ||
| 16831 | If we're in LOCK TABLE mode, we must lock the target tablespace name | ||
| 16832 | as well as the currently used tablesapces (since these may have been | ||
| 16833 | introduced by a previous ALTER while already in LOCK TABLE mode). | ||
| 16834 | */ | ||
| 16835 |
3/4✓ Branch 0 taken 1223 times.
✓ Branch 1 taken 90627 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 91850 times.
|
93073 | if (thd->locked_tables_mode && |
| 16836 |
2/4✓ Branch 0 taken 1223 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1223 times.
|
1223 | get_and_lock_tablespace_names(thd, table_list, nullptr, |
| 16837 | thd->variables.lock_wait_timeout, MYF(0))) { | ||
| 16838 | ✗ | return true; | |
| 16839 | } | ||
| 16840 | |||
| 16841 |
1/2✓ Branch 0 taken 91850 times.
✗ Branch 1 not taken.
|
91850 | if (table_list->table->s->db_type() != create_info->db_type && |
| 16842 |
6/6✓ Branch 0 taken 88885 times.
✓ Branch 1 taken 2965 times.
✓ Branch 2 taken 25515 times.
✓ Branch 3 taken 63370 times.
✓ Branch 4 taken 943 times.
✓ Branch 5 taken 90907 times.
|
117365 | (alter_info->flags & Alter_info::ALTER_OPTIONS) && |
| 16843 |
2/2✓ Branch 0 taken 943 times.
✓ Branch 1 taken 24572 times.
|
25515 | (create_info->used_fields & HA_CREATE_USED_ENGINE)) { |
| 16844 |
1/2✓ Branch 0 taken 943 times.
✗ Branch 1 not taken.
|
943 | handlerton *actual_hton = get_viable_handlerton_for_alter( |
| 16845 |
1/2✓ Branch 0 taken 943 times.
✗ Branch 1 not taken.
|
943 | thd, *create_info, table_list->table->s->db_type()); |
| 16846 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 939 times.
|
943 | if (actual_hton == nullptr) return true; |
| 16847 | |||
| 16848 | 939 | create_info->db_type = actual_hton; | |
| 16849 | } | ||
| 16850 | |||
| 16851 | 91846 | const handlerton *hton = create_info->db_type; | |
| 16852 |
2/2✓ Branch 0 taken 87942 times.
✓ Branch 1 taken 3904 times.
|
91846 | if (hton == nullptr) { |
| 16853 |
1/2✓ Branch 0 taken 87942 times.
✗ Branch 1 not taken.
|
87942 | hton = table_list->table->s->db_type(); |
| 16854 | } | ||
| 16855 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 91846 times.
|
91846 | assert(hton != nullptr); |
| 16856 |
4/4✓ Branch 0 taken 41 times.
✓ Branch 1 taken 91805 times.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 91825 times.
|
91887 | if ((alter_info->flags & Alter_info::ANY_ENGINE_ATTRIBUTE) != 0 && |
| 16857 |
1/2✓ Branch 0 taken 41 times.
✗ Branch 1 not taken.
|
41 | ((hton->flags & HTON_SUPPORTS_ENGINE_ATTRIBUTE) == 0 && |
| 16858 |
3/4✓ Branch 0 taken 41 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 20 times.
|
41 | DBUG_EVALUATE_IF("simulate_engine_attribute_support", false, true))) { |
| 16859 |
2/4✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
|
21 | my_error(ER_ENGINE_ATTRIBUTE_NOT_SUPPORTED, MYF(0), |
| 16860 | ha_resolve_storage_engine_name(hton)); | ||
| 16861 | 21 | return true; | |
| 16862 | } | ||
| 16863 | |||
| 16864 | 91825 | TABLE *table = table_list->table; | |
| 16865 |
1/2✓ Branch 0 taken 91825 times.
✗ Branch 1 not taken.
|
91825 | table->use_all_columns(); |
| 16866 | 91825 | MDL_ticket *mdl_ticket = table->mdl_ticket; | |
| 16867 | |||
| 16868 | /* | ||
| 16869 | Prohibit changing of the UNION list of a non-temporary MERGE table | ||
| 16870 | under LOCK tables. It would be quite difficult to reuse a shrunk | ||
| 16871 | set of tables from the old table or to open a new TABLE object for | ||
| 16872 | an extended list and verify that they belong to locked tables. | ||
| 16873 | */ | ||
| 16874 |
2/2✓ Branch 0 taken 90602 times.
✓ Branch 1 taken 1223 times.
|
91825 | if ((thd->locked_tables_mode == LTM_LOCK_TABLES || |
| 16875 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 90602 times.
|
90602 | thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES) && |
| 16876 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1223 times.
|
1223 | (create_info->used_fields & HA_CREATE_USED_UNION) && |
| 16877 | ✗ | (table->s->tmp_table == NO_TMP_TABLE)) { | |
| 16878 | ✗ | my_error(ER_LOCK_OR_ACTIVE_TRANSACTION, MYF(0)); | |
| 16879 | ✗ | return true; | |
| 16880 | } | ||
| 16881 | |||
| 16882 |
1/2✓ Branch 0 taken 91825 times.
✗ Branch 1 not taken.
|
91825 | Alter_table_ctx alter_ctx(thd, table_list, tables_opened, new_db, new_name); |
| 16883 | |||
| 16884 | /* | ||
| 16885 | Acquire and keep schema locks until commit time, so the DD layer can | ||
| 16886 | safely assert that we have proper MDL on objects stored in the DD. | ||
| 16887 | */ | ||
| 16888 | 91825 | dd::Schema_MDL_locker mdl_locker_1(thd), mdl_locker_2(thd); | |
| 16889 | 91825 | const dd::Schema *schema = nullptr; | |
| 16890 | 91825 | const dd::Schema *new_schema = nullptr; | |
| 16891 | 91825 | const dd::Table *old_table_def = nullptr; | |
| 16892 | /* | ||
| 16893 | This releaser allows us to keep uncommitted DD objects cached | ||
| 16894 | in the Dictionary_client until commit time. | ||
| 16895 | */ | ||
| 16896 |
1/2✓ Branch 0 taken 91825 times.
✗ Branch 1 not taken.
|
91825 | dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client()); |
| 16897 | 367300 | if (mdl_locker_1.ensure_locked(alter_ctx.db) || | |
| 16898 |
2/4✓ Branch 0 taken 91825 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 91825 times.
✗ Branch 3 not taken.
|
91825 | mdl_locker_2.ensure_locked(alter_ctx.new_db) || |
| 16899 |
6/14✓ Branch 0 taken 91825 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 91825 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 91825 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 91825 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 91825 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 91825 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
|
367300 | thd->dd_client()->acquire(alter_ctx.db, &schema) || |
| 16900 |
5/12✓ Branch 0 taken 91825 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 91825 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 91825 times.
✓ Branch 6 taken 91825 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 91825 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
183650 | thd->dd_client()->acquire(alter_ctx.new_db, &new_schema)) |
| 16901 | ✗ | return true; | |
| 16902 | |||
| 16903 |
2/2✓ Branch 0 taken 90642 times.
✓ Branch 1 taken 1183 times.
|
182467 | if ((table->s->tmp_table == NO_TMP_TABLE) && |
| 16904 |
9/18✓ Branch 0 taken 90642 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 90642 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 90642 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 90642 times.
✓ Branch 8 taken 90642 times.
✓ Branch 9 taken 1183 times.
✓ Branch 10 taken 90642 times.
✓ Branch 11 taken 1183 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 91825 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
|
182467 | thd->dd_client()->acquire(alter_ctx.db, alter_ctx.table_name, |
| 16905 | &old_table_def)) | ||
| 16906 | ✗ | return true; | |
| 16907 | |||
| 16908 | // If this is a temporary table, the schema might not exist even | ||
| 16909 | // if we have successfully opened the table | ||
| 16910 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 91824 times.
|
91825 | if (schema == nullptr) { |
| 16911 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | assert(table->s->tmp_table); |
| 16912 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_BAD_DB_ERROR, MYF(0), alter_ctx.db); |
| 16913 | 1 | return true; | |
| 16914 | } | ||
| 16915 | |||
| 16916 |
3/4✓ Branch 0 taken 90642 times.
✓ Branch 1 taken 1182 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 90642 times.
|
91824 | assert((table->s->tmp_table != NO_TMP_TABLE) || old_table_def != nullptr); |
| 16917 | |||
| 16918 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 91823 times.
|
91824 | if (new_schema == nullptr) { |
| 16919 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_BAD_DB_ERROR, MYF(0), alter_ctx.new_db); |
| 16920 | 1 | return true; | |
| 16921 | } | ||
| 16922 | |||
| 16923 | /* | ||
| 16924 | Add old and new (if any) databases to the list of accessed databases | ||
| 16925 | for this statement. Needed for MTS. | ||
| 16926 | */ | ||
| 16927 |
1/2✓ Branch 0 taken 91823 times.
✗ Branch 1 not taken.
|
91823 | thd->add_to_binlog_accessed_dbs(alter_ctx.db); |
| 16928 |
2/2✓ Branch 0 taken 243 times.
✓ Branch 1 taken 91580 times.
|
91823 | if (alter_ctx.is_database_changed()) |
| 16929 |
1/2✓ Branch 0 taken 243 times.
✗ Branch 1 not taken.
|
243 | thd->add_to_binlog_accessed_dbs(alter_ctx.new_db); |
| 16930 | |||
| 16931 | // Ensure that triggers are in the same schema as their subject table. | ||
| 16932 |
6/6✓ Branch 0 taken 243 times.
✓ Branch 1 taken 91580 times.
✓ Branch 2 taken 242 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 91821 times.
|
92065 | if (alter_ctx.is_database_changed() && old_table_def != nullptr && |
| 16933 |
3/4✓ Branch 0 taken 242 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 240 times.
|
242 | old_table_def->has_trigger()) { |
| 16934 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | my_error(ER_TRG_IN_WRONG_SCHEMA, MYF(0)); |
| 16935 | 2 | return true; | |
| 16936 | } | ||
| 16937 | |||
| 16938 | /* Check that we are not trying to rename to an existing table */ | ||
| 16939 |
2/2✓ Branch 0 taken 1092 times.
✓ Branch 1 taken 90729 times.
|
91821 | if (alter_ctx.is_table_renamed()) { |
| 16940 |
2/2✓ Branch 0 taken 20 times.
✓ Branch 1 taken 1072 times.
|
1092 | if (table->s->tmp_table != NO_TMP_TABLE) { |
| 16941 |
3/4✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 18 times.
|
20 | if (find_temporary_table(thd, alter_ctx.new_db, alter_ctx.new_name)) { |
| 16942 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | my_error(ER_TABLE_EXISTS_ERROR, MYF(0), alter_ctx.new_alias); |
| 16943 | 2 | return true; | |
| 16944 | } | ||
| 16945 | } else { | ||
| 16946 |
1/2✓ Branch 0 taken 1072 times.
✗ Branch 1 not taken.
|
1072 | MDL_request_list mdl_requests; |
| 16947 | |||
| 16948 |
1/2✓ Branch 0 taken 1072 times.
✗ Branch 1 not taken.
|
1072 | mdl_requests.push_front(&alter_ctx.target_mdl_request); |
| 16949 | /* | ||
| 16950 | If we are moving the table to a different database, we also | ||
| 16951 | need IX lock on the database name so that the target database | ||
| 16952 | is protected by MDL while the table is moved. | ||
| 16953 | */ | ||
| 16954 |
2/2✓ Branch 0 taken 240 times.
✓ Branch 1 taken 832 times.
|
1072 | if (alter_ctx.is_database_changed()) |
| 16955 |
1/2✓ Branch 0 taken 240 times.
✗ Branch 1 not taken.
|
240 | mdl_requests.push_front(&alter_ctx.target_db_mdl_request); |
| 16956 | |||
| 16957 | /* | ||
| 16958 | Global intention exclusive lock must have been already acquired when | ||
| 16959 | table to be altered was open, so there is no need to do it here. | ||
| 16960 | */ | ||
| 16961 |
2/4✓ Branch 0 taken 1072 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1072 times.
|
1072 | assert(thd->mdl_context.owns_equal_or_stronger_lock( |
| 16962 | MDL_key::GLOBAL, "", "", MDL_INTENTION_EXCLUSIVE)); | ||
| 16963 | |||
| 16964 |
2/4✓ Branch 0 taken 1072 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1072 times.
|
1072 | if (thd->mdl_context.acquire_locks(&mdl_requests, |
| 16965 | thd->variables.lock_wait_timeout)) | ||
| 16966 | 4 | return true; | |
| 16967 | |||
| 16968 |
2/4✓ Branch 0 taken 1072 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1072 times.
✗ Branch 3 not taken.
|
1072 | DEBUG_SYNC(thd, "locked_table_name"); |
| 16969 | /* | ||
| 16970 | Table maybe does not exist, but we got an exclusive lock | ||
| 16971 | on the name, now we can safely try to find out for sure. | ||
| 16972 | */ | ||
| 16973 | 1072 | const dd::Abstract_table *at = nullptr; | |
| 16974 |
4/8✓ Branch 0 taken 1072 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1072 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1072 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1072 times.
|
1072 | if (thd->dd_client()->acquire(alter_ctx.new_db, alter_ctx.new_name, &at)) |
| 16975 | ✗ | return true; | |
| 16976 | |||
| 16977 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1068 times.
|
1072 | if (at != nullptr) { |
| 16978 | /* Table will be closed in do_command() */ | ||
| 16979 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | my_error(ER_TABLE_EXISTS_ERROR, MYF(0), alter_ctx.new_alias); |
| 16980 | 4 | return true; | |
| 16981 | } | ||
| 16982 | } | ||
| 16983 | } | ||
| 16984 | |||
| 16985 |
2/2✓ Branch 0 taken 87911 times.
✓ Branch 1 taken 3904 times.
|
91815 | if (!create_info->db_type) { |
| 16986 |
3/4✓ Branch 0 taken 2892 times.
✓ Branch 1 taken 85019 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2892 times.
|
87911 | if (table->part_info && create_info->used_fields & HA_CREATE_USED_ENGINE) { |
| 16987 | /* | ||
| 16988 | This case happens when the user specified | ||
| 16989 | ENGINE = x where x is a non-existing storage engine | ||
| 16990 | We set create_info->db_type to default_engine_type | ||
| 16991 | to ensure we don't change underlying engine type | ||
| 16992 | due to a erroneously given engine name. | ||
| 16993 | */ | ||
| 16994 | ✗ | create_info->db_type = table->part_info->default_engine_type; | |
| 16995 | } else | ||
| 16996 |
1/2✓ Branch 0 taken 87911 times.
✗ Branch 1 not taken.
|
87911 | create_info->db_type = table->s->db_type(); |
| 16997 | } | ||
| 16998 | |||
| 16999 |
3/4✓ Branch 0 taken 91815 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 87 times.
✓ Branch 3 taken 91728 times.
|
91815 | if (check_engine(thd, alter_ctx.new_db, alter_ctx.new_name, create_info, |
| 17000 | alter_info)) | ||
| 17001 | 87 | return true; | |
| 17002 | |||
| 17003 | /* | ||
| 17004 | Do not allow change of storage engine if table participates in a foreign | ||
| 17005 | key. Even in cases when both source and target storage engines support | ||
| 17006 | foreign keys the fine details of what is supported might differ. | ||
| 17007 | */ | ||
| 17008 |
9/10✓ Branch 0 taken 91728 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 859 times.
✓ Branch 3 taken 90869 times.
✓ Branch 4 taken 845 times.
✓ Branch 5 taken 14 times.
✓ Branch 6 taken 844 times.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 3 times.
✓ Branch 9 taken 91725 times.
|
93417 | if (create_info->db_type != table->s->db_type() && old_table_def != nullptr && |
| 17009 |
3/4✓ Branch 0 taken 845 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 842 times.
|
1689 | (old_table_def->foreign_keys().size() || |
| 17010 |
1/2✓ Branch 0 taken 844 times.
✗ Branch 1 not taken.
|
844 | old_table_def->foreign_key_parents().size())) { |
| 17011 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | my_error(ER_FK_CANNOT_CHANGE_ENGINE, MYF(0)); |
| 17012 | 3 | return true; | |
| 17013 | } | ||
| 17014 | |||
| 17015 | /* | ||
| 17016 | If foreign key is added then check permission to access parent table. | ||
| 17017 | |||
| 17018 | In function "check_fk_parent_table_access", create_info->db_type is used | ||
| 17019 | to identify whether engine supports FK constraint or not. Since | ||
| 17020 | create_info->db_type is set here, check to parent table access is delayed | ||
| 17021 | till this point for the alter operation. | ||
| 17022 | */ | ||
| 17023 |
3/4✓ Branch 0 taken 244 times.
✓ Branch 1 taken 91481 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 91725 times.
|
91969 | if ((alter_info->flags & Alter_info::ADD_FOREIGN_KEY) && |
| 17024 |
2/4✓ Branch 0 taken 244 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 244 times.
|
244 | check_fk_parent_table_access(thd, create_info, alter_info)) |
| 17025 | ✗ | return true; | |
| 17026 | |||
| 17027 | 91725 | Foreign_key_parents_invalidator fk_invalidator; | |
| 17028 | |||
| 17029 |
2/2✓ Branch 0 taken 90545 times.
✓ Branch 1 taken 1180 times.
|
91725 | if (table->s->tmp_table == NO_TMP_TABLE) { |
| 17030 |
1/2✓ Branch 0 taken 90545 times.
✗ Branch 1 not taken.
|
90545 | MDL_request_list mdl_requests; |
| 17031 | |||
| 17032 |
2/4✓ Branch 0 taken 90545 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 90545 times.
|
90545 | if (collect_fk_parents_for_new_fks( |
| 17033 | thd, table_list->db, table_list->table_name, alter_info, | ||
| 17034 | MDL_SHARED_UPGRADABLE, nullptr, &mdl_requests, nullptr)) | ||
| 17035 | 2 | return true; | |
| 17036 | |||
| 17037 | /* | ||
| 17038 | Acquire SU locks on parent and child tables so we can access | ||
| 17039 | their definition while checking if this ALTER TABLE will break | ||
| 17040 | any FKs involving them. | ||
| 17041 | |||
| 17042 | TODO: Refine set of ALTER TABLE commands for which we do this. | ||
| 17043 | This is obviously necessary for ADD/DROP KEY and COLUMN | ||
| 17044 | modifications. But are there any other operations which | ||
| 17045 | might affect indexes somehow? | ||
| 17046 | */ | ||
| 17047 |
2/2✓ Branch 0 taken 88502 times.
✓ Branch 1 taken 2043 times.
|
90545 | if (!is_simple_rename_or_index_change(alter_info)) { |
| 17048 |
2/4✓ Branch 0 taken 88502 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 88502 times.
|
88502 | if (collect_fk_parents_for_all_fks(thd, old_table_def, nullptr, |
| 17049 | MDL_SHARED_UPGRADABLE, &mdl_requests, | ||
| 17050 | nullptr)) | ||
| 17051 | ✗ | return true; | |
| 17052 | |||
| 17053 |
3/4✓ Branch 0 taken 88502 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 842 times.
✓ Branch 3 taken 87660 times.
|
88502 | if (create_info->db_type != table->s->db_type()) { |
| 17054 | /* | ||
| 17055 | By changing table's storage engine we might be introducing parent | ||
| 17056 | table for previously orphan foreign keys in the new SE. We need | ||
| 17057 | to lock child tables of such orphan foreign keys. OTOH it is safe | ||
| 17058 | to assume that if SE is changed table can't be parent in any | ||
| 17059 | foreign keys in old SE. | ||
| 17060 | |||
| 17061 | Note that here and in other similar places we assume that ALTER | ||
| 17062 | TABLE which combines change of SE and renaming of table is executed | ||
| 17063 | by changing SE first and then performing rename (this is closer to | ||
| 17064 | ALTER TABLE real implementation). Because of this such ALTER TABLEs | ||
| 17065 | need to pick up orphan foreign keys associated with old table names | ||
| 17066 | as well. Thus we use old table name to get list of orphans. | ||
| 17067 | */ | ||
| 17068 |
2/4✓ Branch 0 taken 842 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 842 times.
|
842 | assert(old_table_def->foreign_key_parents().size() == 0); |
| 17069 | |||
| 17070 |
2/4✓ Branch 0 taken 842 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 842 times.
|
842 | if (collect_fk_children(thd, table_list->db, table_list->table_name, |
| 17071 | create_info->db_type, MDL_SHARED_UPGRADABLE, | ||
| 17072 | &mdl_requests)) | ||
| 17073 | ✗ | return true; | |
| 17074 | } else { | ||
| 17075 |
2/4✓ Branch 0 taken 87660 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 87660 times.
|
87660 | if (collect_fk_children(thd, old_table_def, MDL_SHARED_UPGRADABLE, |
| 17076 | &mdl_requests)) | ||
| 17077 | ✗ | return true; | |
| 17078 | } | ||
| 17079 | |||
| 17080 |
3/4✓ Branch 0 taken 297 times.
✓ Branch 1 taken 88205 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 88502 times.
|
88799 | if (alter_ctx.is_table_renamed() && |
| 17081 |
2/4✓ Branch 0 taken 297 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 297 times.
|
297 | collect_fk_children(thd, alter_ctx.new_db, alter_ctx.new_alias, |
| 17082 | create_info->db_type, MDL_SHARED_UPGRADABLE, | ||
| 17083 | &mdl_requests)) | ||
| 17084 | ✗ | return true; | |
| 17085 | } | ||
| 17086 | |||
| 17087 | /* | ||
| 17088 | Lock names of foreign keys to be dropped. | ||
| 17089 | |||
| 17090 | Note that we can't lock names of foreign keys to be added yet | ||
| 17091 | because database in which they will be created depends on ALTER | ||
| 17092 | TABLE algorithm we are going to choose later. | ||
| 17093 | */ | ||
| 17094 |
2/4✓ Branch 0 taken 90545 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 90545 times.
|
90545 | if (collect_fk_names_for_dropped_fks(thd, table_list->db, alter_info, |
| 17095 | old_table_def, &mdl_requests)) | ||
| 17096 | ✗ | return true; | |
| 17097 | |||
| 17098 | /* | ||
| 17099 | Under LOCK TABLES all parent tables must be locked at least in READ | ||
| 17100 | mode. Otherwise, our ALTER TABLE will leave after itself child table | ||
| 17101 | locked for WRITE, without corresponding parent tables locked and thus | ||
| 17102 | without ability to perform FK checks when child table is modified. | ||
| 17103 | */ | ||
| 17104 |
2/2✓ Branch 0 taken 89323 times.
✓ Branch 1 taken 1222 times.
|
90545 | if (thd->locked_tables_mode == LTM_LOCK_TABLES || |
| 17105 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 89323 times.
|
89323 | thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES) { |
| 17106 | 1222 | MDL_request_list::Iterator it(mdl_requests); | |
| 17107 | MDL_request *mdl_request; | ||
| 17108 | |||
| 17109 |
3/4✓ Branch 0 taken 1229 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 1221 times.
|
1229 | while ((mdl_request = it++) != nullptr) { |
| 17110 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
|
8 | if (mdl_request->key.mdl_namespace() != MDL_key::TABLE) continue; |
| 17111 | |||
| 17112 |
4/6✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 3 times.
|
4 | if (!thd->mdl_context.owns_equal_or_stronger_lock( |
| 17113 | MDL_key::TABLE, mdl_request->key.db_name(), | ||
| 17114 | mdl_request->key.name(), MDL_SHARED_READ_ONLY)) { | ||
| 17115 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | my_error(ER_TABLE_NOT_LOCKED, MYF(0), mdl_request->key.name()); |
| 17116 | 1 | return true; | |
| 17117 | } | ||
| 17118 | } | ||
| 17119 | } | ||
| 17120 | |||
| 17121 |
3/4✓ Branch 0 taken 583 times.
✓ Branch 1 taken 89961 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 90544 times.
|
91127 | if (!mdl_requests.is_empty() && |
| 17122 |
2/4✓ Branch 0 taken 583 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 583 times.
|
583 | thd->mdl_context.acquire_locks(&mdl_requests, |
| 17123 | thd->variables.lock_wait_timeout)) | ||
| 17124 | ✗ | return true; | |
| 17125 | |||
| 17126 |
3/4✓ Branch 0 taken 88164 times.
✓ Branch 1 taken 2380 times.
✓ Branch 2 taken 88164 times.
✗ Branch 3 not taken.
|
90544 | DEBUG_SYNC(thd, "alter_table_after_mdl_lock_fk"); |
| 17127 | |||
| 17128 | /* | ||
| 17129 | If we are executing ALTER TABLE RENAME under LOCK TABLES we also need | ||
| 17130 | to check that all previously orphan tables which reference new table | ||
| 17131 | name through foreign keys are locked for write. Otherwise this ALTER | ||
| 17132 | will leave after itself parent table locked for WRITE without child | ||
| 17133 | tables locked for WRITE. This will break FK LOCK TABLES invariants if | ||
| 17134 | some of previously orphan FKs have referential actions which update | ||
| 17135 | child table. | ||
| 17136 | |||
| 17137 | The same should be done when we are going to add parent table to | ||
| 17138 | previously orphan foreign keys by changing table storage engine. | ||
| 17139 | |||
| 17140 | In theory, we can reduce chance of MDL deadlocks by also checking at | ||
| 17141 | this stage that all child and parent tables for FKs in which this | ||
| 17142 | table participates are locked for WRITE (as we will have to acquire | ||
| 17143 | to exclusive MDLs on these tables later). But this is, probably, too | ||
| 17144 | severe restriction since many 3rd-party online ALTER tools use ALTER | ||
| 17145 | TABLE RENAME under LOCK TABLES and are unaware of it. | ||
| 17146 | */ | ||
| 17147 |
2/2✓ Branch 0 taken 89323 times.
✓ Branch 1 taken 1221 times.
|
90544 | if (thd->locked_tables_mode == LTM_LOCK_TABLES || |
| 17148 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 89323 times.
|
89323 | thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES) { |
| 17149 |
1/2✓ Branch 0 taken 1221 times.
✗ Branch 1 not taken.
|
1221 | MDL_request_list orphans_mdl_requests; |
| 17150 | |||
| 17151 |
3/4✓ Branch 0 taken 1221 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 1216 times.
|
1221 | if (create_info->db_type != table->s->db_type()) { |
| 17152 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
|
5 | assert(old_table_def->foreign_key_parents().size() == 0); |
| 17153 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
|
5 | if (collect_fk_children(thd, table_list->db, table_list->table_name, |
| 17154 | create_info->db_type, MDL_EXCLUSIVE, | ||
| 17155 | &orphans_mdl_requests)) | ||
| 17156 | 1 | return true; | |
| 17157 | } | ||
| 17158 |
3/4✓ Branch 0 taken 29 times.
✓ Branch 1 taken 1192 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1221 times.
|
1250 | if (alter_ctx.is_table_renamed() && |
| 17159 |
2/4✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 29 times.
|
29 | collect_fk_children(thd, alter_ctx.new_db, alter_ctx.new_alias, |
| 17160 | create_info->db_type, MDL_EXCLUSIVE, | ||
| 17161 | &orphans_mdl_requests)) | ||
| 17162 | ✗ | return true; | |
| 17163 | |||
| 17164 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1219 times.
|
1221 | if (!orphans_mdl_requests.is_empty()) { |
| 17165 | 2 | MDL_request_list::Iterator it(orphans_mdl_requests); | |
| 17166 | MDL_request *mdl_request; | ||
| 17167 | |||
| 17168 |
3/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 1 times.
|
5 | while ((mdl_request = it++) != nullptr) { |
| 17169 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | if (mdl_request->key.mdl_namespace() != MDL_key::TABLE) continue; |
| 17170 | |||
| 17171 |
4/6✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
|
2 | if (!thd->mdl_context.owns_equal_or_stronger_lock( |
| 17172 | MDL_key::TABLE, mdl_request->key.db_name(), | ||
| 17173 | mdl_request->key.name(), MDL_SHARED_NO_READ_WRITE)) { | ||
| 17174 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), |
| 17175 | mdl_request->key.name()); | ||
| 17176 | 1 | return true; | |
| 17177 | } | ||
| 17178 | } | ||
| 17179 | } | ||
| 17180 | } | ||
| 17181 | } | ||
| 17182 | |||
| 17183 | /* | ||
| 17184 | If this is an ALTER TABLE and no explicit row type specified reuse | ||
| 17185 | the table's row type. | ||
| 17186 | Note : this is the same as if the row type was specified explicitly. | ||
| 17187 | */ | ||
| 17188 |
2/2✓ Branch 0 taken 86410 times.
✓ Branch 1 taken 5313 times.
|
91723 | if (create_info->row_type == ROW_TYPE_NOT_USED) { |
| 17189 | /* ALTER TABLE without explicit row type */ | ||
| 17190 | 86410 | create_info->row_type = table->s->row_type; | |
| 17191 | } else { | ||
| 17192 | /* ALTER TABLE with specific row type */ | ||
| 17193 | 5313 | create_info->used_fields |= HA_CREATE_USED_ROW_FORMAT; | |
| 17194 | } | ||
| 17195 | |||
| 17196 |
8/14✓ Branch 0 taken 91723 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 91723 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 91721 times.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 2 times.
✗ Branch 13 not taken.
|
91723 | DBUG_PRINT("info", ("old type: %s new type: %s", |
| 17197 | ha_resolve_storage_engine_name(table->s->db_type()), | ||
| 17198 | ha_resolve_storage_engine_name(create_info->db_type))); | ||
| 17199 |
1/2✓ Branch 0 taken 91723 times.
✗ Branch 1 not taken.
|
91723 | if (ha_check_storage_engine_flag(table->s->db_type(), |
| 17200 |
5/6✓ Branch 0 taken 91722 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 91722 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 91722 times.
|
183445 | HTON_ALTER_NOT_SUPPORTED) || |
| 17201 | 91722 | ha_check_storage_engine_flag(create_info->db_type, | |
| 17202 | HTON_ALTER_NOT_SUPPORTED)) { | ||
| 17203 |
3/8✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
1 | DBUG_PRINT("info", ("doesn't support alter")); |
| 17204 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_ILLEGAL_HA, MYF(0), table_list->table_name); |
| 17205 | 1 | return true; | |
| 17206 | } | ||
| 17207 | |||
| 17208 |
1/2✓ Branch 0 taken 91722 times.
✗ Branch 1 not taken.
|
91722 | THD_STAGE_INFO(thd, stage_setup); |
| 17209 | |||
| 17210 |
6/6✓ Branch 0 taken 2060 times.
✓ Branch 1 taken 89662 times.
✓ Branch 2 taken 2043 times.
✓ Branch 3 taken 17 times.
✓ Branch 4 taken 2043 times.
✓ Branch 5 taken 89679 times.
|
91722 | if (is_simple_rename_or_index_change(alter_info) && !table->s->tmp_table) { |
| 17211 | // This requires X-lock, no other lock levels supported. | ||
| 17212 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 2027 times.
|
2043 | if (alter_info->requested_lock != Alter_info::ALTER_TABLE_LOCK_DEFAULT && |
| 17213 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 6 times.
|
16 | alter_info->requested_lock != Alter_info::ALTER_TABLE_LOCK_EXCLUSIVE) { |
| 17214 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | my_error(ER_ALTER_OPERATION_NOT_SUPPORTED, MYF(0), "LOCK=NONE/SHARED", |
| 17215 | "LOCK=EXCLUSIVE"); | ||
| 17216 | 10 | return true; | |
| 17217 | } | ||
| 17218 |
1/2✓ Branch 0 taken 2024 times.
✗ Branch 1 not taken.
|
2033 | return simple_rename_or_index_change(thd, *new_schema, table_list, |
| 17219 | 2024 | alter_info->keys_onoff, &alter_ctx); | |
| 17220 | } | ||
| 17221 | |||
| 17222 | /* We have to do full alter table. */ | ||
| 17223 | 89679 | bool partition_changed = false; | |
| 17224 | 89679 | partition_info *new_part_info = nullptr; | |
| 17225 | { | ||
| 17226 |
3/4✓ Branch 0 taken 89679 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 137 times.
✓ Branch 3 taken 89542 times.
|
89679 | if (prep_alter_part_table(thd, table, alter_info, create_info, &alter_ctx, |
| 17227 | &partition_changed, &new_part_info)) { | ||
| 17228 | 137 | return true; | |
| 17229 | } | ||
| 17230 | } | ||
| 17231 |
5/8✓ Branch 0 taken 1093 times.
✓ Branch 1 taken 88449 times.
✓ Branch 2 taken 1093 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1093 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 89542 times.
|
89542 | if (new_part_info != nullptr && alter_info->has_compressed_columns() && |
| 17232 | ✗ | !ha_check_storage_engine_flag(new_part_info->default_engine_type, | |
| 17233 | HTON_SUPPORTS_COMPRESSED_COLUMNS)) { | ||
| 17234 | ✗ | my_error(ER_ILLEGAL_HA_CREATE_OPTION, MYF(0), | |
| 17235 | ✗ | ha_resolve_storage_engine_name(new_part_info->default_engine_type), | |
| 17236 | "COMPRESSED COLUMNS"); | ||
| 17237 | ✗ | return true; | |
| 17238 | } | ||
| 17239 | |||
| 17240 | /* | ||
| 17241 | Store all columns that are going to be dropped, since we need this list | ||
| 17242 | when removing column statistics later. The reason we need to store it here, | ||
| 17243 | is that 'mysql_prepare_alter_table' may remove some of the columns from | ||
| 17244 | the drop_list. | ||
| 17245 | */ | ||
| 17246 | 89542 | histograms::columns_set columns; | |
| 17247 |
3/4✓ Branch 0 taken 89542 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12132 times.
✓ Branch 3 taken 89542 times.
|
101674 | for (const auto column : alter_info->drop_list) { |
| 17248 |
3/4✓ Branch 0 taken 3174 times.
✓ Branch 1 taken 8958 times.
✓ Branch 2 taken 3174 times.
✗ Branch 3 not taken.
|
12132 | if (column->type == Alter_drop::COLUMN) columns.emplace(column->name); |
| 17249 | } | ||
| 17250 | 89542 | const Alter_column *alter = nullptr; | |
| 17251 | 89542 | uint i = 0; | |
| 17252 |
2/2✓ Branch 0 taken 360 times.
✓ Branch 1 taken 89542 times.
|
89902 | while (i < alter_info->alter_list.size()) { |
| 17253 |
1/2✓ Branch 0 taken 360 times.
✗ Branch 1 not taken.
|
360 | alter = alter_info->alter_list[i]; |
| 17254 |
2/2✓ Branch 0 taken 101 times.
✓ Branch 1 taken 259 times.
|
360 | if (alter->change_type() == Alter_column::Type::RENAME_COLUMN) |
| 17255 |
1/2✓ Branch 0 taken 101 times.
✗ Branch 1 not taken.
|
101 | columns.emplace(alter->name); |
| 17256 | 360 | i++; | |
| 17257 | } | ||
| 17258 | |||
| 17259 | Create_field *create_field; | ||
| 17260 |
1/2✓ Branch 0 taken 89542 times.
✗ Branch 1 not taken.
|
89542 | List_iterator<Create_field> list_it(alter_info->create_list); |
| 17261 |
2/2✓ Branch 0 taken 61269 times.
✓ Branch 1 taken 89542 times.
|
150811 | while ((create_field = list_it++)) { |
| 17262 |
3/4✓ Branch 0 taken 30303 times.
✓ Branch 1 taken 30966 times.
✓ Branch 2 taken 30303 times.
✗ Branch 3 not taken.
|
61269 | if (create_field->change != nullptr) columns.emplace(create_field->change); |
| 17263 | } | ||
| 17264 | |||
| 17265 | /* | ||
| 17266 | Type of a constraint marked for DROP with DROP CONSTRAINT clause is unknown. | ||
| 17267 | Resolve type of a constraint by name. | ||
| 17268 | */ | ||
| 17269 | 89542 | Drop_constraint_type_resolver drop_constraint_type_resolver(alter_info); | |
| 17270 |
5/6✓ Branch 0 taken 89542 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 38 times.
✓ Branch 3 taken 89504 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 89538 times.
|
89580 | if (drop_constraint_type_resolver.is_type_resolution_needed() && |
| 17271 |
3/4✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 34 times.
|
38 | (drop_constraint_type_resolver.resolve_constraints_type(thd, table, |
| 17272 | old_table_def))) | ||
| 17273 | 4 | return true; | |
| 17274 | |||
| 17275 | /* | ||
| 17276 | Type of a constraint marked for ALTER with ALTER CONSTRAINT clause is | ||
| 17277 | unknown. Resolve type of a constraint by name. | ||
| 17278 | */ | ||
| 17279 | 89538 | Enforce_constraint_type_resolver enforce_constraint_type_resolver(alter_info); | |
| 17280 |
5/6✓ Branch 0 taken 89538 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
✓ Branch 3 taken 89518 times.
✓ Branch 4 taken 11 times.
✓ Branch 5 taken 89527 times.
|
89558 | if (enforce_constraint_type_resolver.is_type_resolution_needed() && |
| 17281 |
3/4✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 9 times.
|
20 | (enforce_constraint_type_resolver.resolve_constraints_type( |
| 17282 | thd, table, old_table_def))) | ||
| 17283 | 11 | return true; | |
| 17284 | |||
| 17285 | // Prepare check constraints for alter table operation. | ||
| 17286 |
3/4✓ Branch 0 taken 89527 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 89499 times.
|
89527 | if (prepare_check_constraints_for_alter(thd, table, alter_info, &alter_ctx)) |
| 17287 | 28 | return true; | |
| 17288 | |||
| 17289 |
4/4✓ Branch 0 taken 18924 times.
✓ Branch 1 taken 70575 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 89496 times.
|
108423 | if ((alter_info->flags & Alter_info::ALTER_ADD_COLUMN) != 0 && |
| 17290 |
3/4✓ Branch 0 taken 18924 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 18921 times.
|
18924 | alter_info->has_compressed_columns()) { |
| 17291 |
1/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
3 | switch (alter_info->requested_algorithm) { |
| 17292 | 3 | case Alter_info::ALTER_TABLE_ALGORITHM_DEFAULT: | |
| 17293 | |||
| 17294 |
3/26✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
|
3 | DBUG_LOG("zip_dict", |
| 17295 | "ALTER query " | ||
| 17296 | << thd->query().str | ||
| 17297 | << " is using INPLACE for add column" | ||
| 17298 | " because one of the ADD COLUMN is compressed column"); | ||
| 17299 | |||
| 17300 | 3 | alter_info->requested_algorithm = | |
| 17301 | Alter_info::ALTER_TABLE_ALGORITHM_INPLACE; | ||
| 17302 | 3 | break; | |
| 17303 | ✗ | case Alter_info::ALTER_TABLE_ALGORITHM_INSTANT: | |
| 17304 | // Not possible, error out. | ||
| 17305 | ✗ | my_error(ER_ALTER_OPERATION_NOT_SUPPORTED, MYF(0), "ALGORITHM=INSTANT", | |
| 17306 | "ALGORITHM=INPLACE/COPY"); | ||
| 17307 | ✗ | return true; | |
| 17308 | ✗ | case Alter_info::ALTER_TABLE_ALGORITHM_COPY: | |
| 17309 | case Alter_info::ALTER_TABLE_ALGORITHM_INPLACE: | ||
| 17310 | ✗ | break; | |
| 17311 | ✗ | default: | |
| 17312 | ✗ | return 0; | |
| 17313 | } | ||
| 17314 | } | ||
| 17315 | |||
| 17316 |
3/4✓ Branch 0 taken 89499 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1203 times.
✓ Branch 3 taken 88296 times.
|
89499 | if (mysql_prepare_alter_table(thd, old_table_def, table, create_info, |
| 17317 | alter_info, &alter_ctx)) { | ||
| 17318 | 1203 | return true; | |
| 17319 | } | ||
| 17320 | |||
| 17321 | // Check restrictions on ALTER TABLE operations that affects GIPK and PK. | ||
| 17322 |
3/4✓ Branch 0 taken 88296 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 41 times.
✓ Branch 3 taken 88255 times.
|
88296 | if (check_primary_key_alter_restrictions(thd, create_info->db_type, |
| 17323 | alter_info, table)) | ||
| 17324 | 41 | return true; | |
| 17325 | |||
| 17326 | /* | ||
| 17327 | Check if we are changing the SRID specification on a geometry column that | ||
| 17328 | has a spatial index. If that is the case, reject the change since allowing | ||
| 17329 | geometries with different SRIDs in a spatial index will make the index | ||
| 17330 | useless. | ||
| 17331 | */ | ||
| 17332 |
3/4✓ Branch 0 taken 88255 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 88244 times.
|
88255 | if (!is_alter_geometry_column_valid(alter_info)) return true; |
| 17333 | |||
| 17334 |
2/4✓ Branch 0 taken 88244 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 88244 times.
|
88244 | if (set_table_default_charset(thd, create_info, *schema)) return true; |
| 17335 | |||
| 17336 | /* | ||
| 17337 | Use copy algorithm if: | ||
| 17338 | - old_alter_table system variable is set without in-place requested using | ||
| 17339 | the ALGORITHM clause. | ||
| 17340 | - Or if in-place is impossible for given operation. | ||
| 17341 | - Changes to partitioning needs to be handled using table copying | ||
| 17342 | algorithm unless the engine supports partitioning changes using | ||
| 17343 | in-place API (because it supports auto-partitioning or simply | ||
| 17344 | can do partitioning changes using in-place using mark-up in | ||
| 17345 | partition_info object). | ||
| 17346 | */ | ||
| 17347 | 176502 | if ((thd->variables.old_alter_table && | |
| 17348 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
|
14 | alter_info->requested_algorithm != |
| 17349 | 13 | Alter_info::ALTER_TABLE_ALGORITHM_INPLACE && | |
| 17350 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
|
13 | alter_info->requested_algorithm != |
| 17351 | 88231 | Alter_info::ALTER_TABLE_ALGORITHM_INSTANT) || | |
| 17352 |
9/10✓ Branch 0 taken 14 times.
✓ Branch 1 taken 88230 times.
✓ Branch 2 taken 88231 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 85994 times.
✓ Branch 5 taken 2237 times.
✓ Branch 6 taken 1788 times.
✓ Branch 7 taken 84206 times.
✓ Branch 8 taken 2946 times.
✓ Branch 9 taken 85298 times.
|
90046 | is_inplace_alter_impossible(table, create_info, alter_info) || |
| 17353 | 1788 | (partition_changed && | |
| 17354 |
3/6✓ Branch 0 taken 1788 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1788 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1788 times.
✗ Branch 5 not taken.
|
1788 | !(table->s->db_type()->partition_flags() & HA_USE_AUTO_PARTITION) && |
| 17355 |
2/2✓ Branch 0 taken 696 times.
✓ Branch 1 taken 1092 times.
|
1788 | !new_part_info)) { |
| 17356 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 2934 times.
|
2946 | if (alter_info->requested_algorithm == |
| 17357 | Alter_info::ALTER_TABLE_ALGORITHM_INPLACE) { | ||
| 17358 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | my_error(ER_ALTER_OPERATION_NOT_SUPPORTED, MYF(0), "ALGORITHM=INPLACE", |
| 17359 | "ALGORITHM=COPY"); | ||
| 17360 | 12 | return true; | |
| 17361 | } | ||
| 17362 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2929 times.
|
2934 | if (alter_info->requested_algorithm == |
| 17363 | Alter_info::ALTER_TABLE_ALGORITHM_INSTANT) { | ||
| 17364 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | my_error(ER_ALTER_OPERATION_NOT_SUPPORTED, MYF(0), "ALGORITHM=INSTANT", |
| 17365 | "ALGORITHM=COPY"); | ||
| 17366 | 5 | return true; | |
| 17367 | } | ||
| 17368 | 2929 | alter_info->requested_algorithm = Alter_info::ALTER_TABLE_ALGORITHM_COPY; | |
| 17369 | } | ||
| 17370 | |||
| 17371 | /* | ||
| 17372 | If 'avoid_temporal_upgrade' mode is not enabled, then the | ||
| 17373 | pre MySQL 5.6.4 old temporal types if present is upgraded to the | ||
| 17374 | current format. | ||
| 17375 | */ | ||
| 17376 | |||
| 17377 |
1/2✓ Branch 0 taken 88227 times.
✗ Branch 1 not taken.
|
88227 | mysql_mutex_lock(&LOCK_global_system_variables); |
| 17378 | 88227 | bool check_temporal_upgrade = !avoid_temporal_upgrade; | |
| 17379 |
1/2✓ Branch 0 taken 88227 times.
✗ Branch 1 not taken.
|
88227 | mysql_mutex_unlock(&LOCK_global_system_variables); |
| 17380 | |||
| 17381 |
1/2✓ Branch 0 taken 88227 times.
✗ Branch 1 not taken.
|
88227 | if (check_temporal_upgrade) { |
| 17382 |
2/4✓ Branch 0 taken 88227 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 88227 times.
|
88227 | if (upgrade_old_temporal_types(thd, alter_info)) return true; |
| 17383 | } | ||
| 17384 | |||
| 17385 | /* | ||
| 17386 | ALTER TABLE ... ENGINE to the same engine is a common way to | ||
| 17387 | request table rebuild. Set ALTER_RECREATE flag to force table | ||
| 17388 | rebuild. | ||
| 17389 | */ | ||
| 17390 |
5/6✓ Branch 0 taken 88227 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 87387 times.
✓ Branch 3 taken 840 times.
✓ Branch 4 taken 2962 times.
✓ Branch 5 taken 85265 times.
|
175614 | if (create_info->db_type == table->s->db_type() && |
| 17391 |
2/2✓ Branch 0 taken 2962 times.
✓ Branch 1 taken 84425 times.
|
87387 | create_info->used_fields & HA_CREATE_USED_ENGINE) |
| 17392 | 2962 | alter_info->flags |= Alter_info::ALTER_RECREATE; | |
| 17393 | |||
| 17394 | /* | ||
| 17395 | If the old table had partitions and we are doing ALTER TABLE ... | ||
| 17396 | engine= <new_engine>, the new table must preserve the original | ||
| 17397 | partitioning. This means that the new engine is still the | ||
| 17398 | partitioning engine, not the engine specified in the parser. | ||
| 17399 | This is discovered in prep_alter_part_table, which in such case | ||
| 17400 | updates create_info->db_type. | ||
| 17401 | It's therefore important that the assignment below is done | ||
| 17402 | after prep_alter_part_table. | ||
| 17403 | */ | ||
| 17404 | 88227 | handlerton *new_db_type = create_info->db_type; | |
| 17405 |
1/2✓ Branch 0 taken 88227 times.
✗ Branch 1 not taken.
|
88227 | handlerton *old_db_type = table->s->db_type(); |
| 17406 | 88227 | TABLE *new_table = nullptr; | |
| 17407 | 88227 | ha_rows copied = 0, deleted = 0; | |
| 17408 | |||
| 17409 | /* | ||
| 17410 | Handling of symlinked tables: | ||
| 17411 | If no rename: | ||
| 17412 | Create new data file and index file on the same disk as the | ||
| 17413 | old data and index files. | ||
| 17414 | Copy data. | ||
| 17415 | Rename new data file over old data file and new index file over | ||
| 17416 | old index file. | ||
| 17417 | Symlinks are not changed. | ||
| 17418 | |||
| 17419 | If rename: | ||
| 17420 | Create new data file and index file on the same disk as the | ||
| 17421 | old data and index files. Create also symlinks to point at | ||
| 17422 | the new tables. | ||
| 17423 | Copy data. | ||
| 17424 | At end, rename intermediate tables, and symlinks to intermediate | ||
| 17425 | table, to final table name. | ||
| 17426 | Remove old table and old symlinks | ||
| 17427 | |||
| 17428 | If rename is made to another database: | ||
| 17429 | Create new tables in new database. | ||
| 17430 | Copy data. | ||
| 17431 | Remove old table and symlinks. | ||
| 17432 | */ | ||
| 17433 | char index_file[FN_REFLEN], data_file[FN_REFLEN]; | ||
| 17434 | |||
| 17435 |
2/2✓ Branch 0 taken 88127 times.
✓ Branch 1 taken 100 times.
|
88227 | if (!alter_ctx.is_database_changed()) { |
| 17436 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 88125 times.
|
88127 | if (create_info->index_file_name) { |
| 17437 | /* Fix index_file_name to have 'tmp_name' as basename */ | ||
| 17438 | 2 | my_stpcpy(index_file, alter_ctx.tmp_name); | |
| 17439 | 2 | create_info->index_file_name = | |
| 17440 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | fn_same(index_file, create_info->index_file_name, 1); |
| 17441 | } | ||
| 17442 |
2/2✓ Branch 0 taken 83 times.
✓ Branch 1 taken 88044 times.
|
88127 | if (create_info->data_file_name) { |
| 17443 | /* Fix data_file_name to have 'tmp_name' as basename */ | ||
| 17444 | 83 | my_stpcpy(data_file, alter_ctx.tmp_name); | |
| 17445 | 83 | create_info->data_file_name = | |
| 17446 |
1/2✓ Branch 0 taken 83 times.
✗ Branch 1 not taken.
|
83 | fn_same(data_file, create_info->data_file_name, 1); |
| 17447 | } | ||
| 17448 | } else { | ||
| 17449 | /* Ignore symlink if db is changed. */ | ||
| 17450 | 100 | create_info->data_file_name = create_info->index_file_name = nullptr; | |
| 17451 | } | ||
| 17452 | |||
| 17453 |
3/4✓ Branch 0 taken 85855 times.
✓ Branch 1 taken 2372 times.
✓ Branch 2 taken 85855 times.
✗ Branch 3 not taken.
|
88227 | DEBUG_SYNC(thd, "alter_table_before_create_table_no_lock"); |
| 17454 |
4/6✓ Branch 0 taken 88227 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 88226 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
88227 | DBUG_EXECUTE_IF("sleep_before_create_table_no_lock", my_sleep(100000);); |
| 17455 | /* | ||
| 17456 | Promote first timestamp column, when explicit_defaults_for_timestamp | ||
| 17457 | is not set | ||
| 17458 | */ | ||
| 17459 |
2/2✓ Branch 0 taken 60 times.
✓ Branch 1 taken 88167 times.
|
88227 | if (!thd->variables.explicit_defaults_for_timestamp) |
| 17460 |
1/2✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
|
60 | promote_first_timestamp_column(&alter_info->create_list); |
| 17461 | |||
| 17462 | /* | ||
| 17463 | Create .FRM for new version of table with a temporary name. | ||
| 17464 | We don't log the statement, it will be logged later. | ||
| 17465 | |||
| 17466 | Keep information about keys in newly created table as it | ||
| 17467 | will be used later to construct Alter_inplace_info object | ||
| 17468 | and by fill_alter_inplace_info() call. | ||
| 17469 | */ | ||
| 17470 | KEY *key_info; | ||
| 17471 | uint key_count; | ||
| 17472 | 88227 | FOREIGN_KEY *fk_key_info = nullptr; | |
| 17473 | 88227 | uint fk_key_count = 0; | |
| 17474 | |||
| 17475 | Alter_info::enum_enable_or_disable keys_onoff = | ||
| 17476 | 176430 | ((alter_info->keys_onoff == Alter_info::LEAVE_AS_IS && | |
| 17477 |
3/4✓ Branch 0 taken 88203 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 88197 times.
✓ Branch 3 taken 6 times.
|
88203 | table->file->indexes_are_disabled()) |
| 17478 |
2/2✓ Branch 0 taken 88203 times.
✓ Branch 1 taken 24 times.
|
176430 | ? Alter_info::DISABLE |
| 17479 | 88227 | : alter_info->keys_onoff); | |
| 17480 | |||
| 17481 | /* | ||
| 17482 | Take the X metadata lock on temporary name used for new version of | ||
| 17483 | the table. This ensures that concurrent I_S queries won't try to open it. | ||
| 17484 | */ | ||
| 17485 | |||
| 17486 | 88227 | MDL_request tmp_name_mdl_request; | |
| 17487 | 88227 | bool is_tmp_table = (table->s->tmp_table != NO_TMP_TABLE); | |
| 17488 | |||
| 17489 | // Avoid these tables to be visible by I_S/SHOW queries. | ||
| 17490 | 88227 | create_info->m_hidden = !is_tmp_table; | |
| 17491 | |||
| 17492 |
2/2✓ Branch 0 taken 87067 times.
✓ Branch 1 taken 1160 times.
|
88227 | if (!is_tmp_table) { |
| 17493 |
1/2✓ Branch 0 taken 87067 times.
✗ Branch 1 not taken.
|
87067 | MDL_REQUEST_INIT(&tmp_name_mdl_request, MDL_key::TABLE, alter_ctx.new_db, |
| 17494 | alter_ctx.tmp_name, MDL_EXCLUSIVE, MDL_STATEMENT); | ||
| 17495 |
2/4✓ Branch 0 taken 87067 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 87067 times.
|
87067 | if (thd->mdl_context.acquire_lock(&tmp_name_mdl_request, |
| 17496 | thd->variables.lock_wait_timeout)) | ||
| 17497 | ✗ | return true; | |
| 17498 | } | ||
| 17499 | |||
| 17500 | // Stop if we have invalid encryption clause. | ||
| 17501 |
7/8✓ Branch 0 taken 87067 times.
✓ Branch 1 taken 1160 times.
✓ Branch 2 taken 87067 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 101 times.
✓ Branch 5 taken 86966 times.
✓ Branch 6 taken 101 times.
✓ Branch 7 taken 88126 times.
|
88227 | if (!is_tmp_table && validate_table_encryption(thd, create_info)) return true; |
| 17502 | |||
| 17503 | /* | ||
| 17504 | For temporary tables or tables in SEs supporting atomic DDL dd::Table | ||
| 17505 | object describing new version of table. This object will be created in | ||
| 17506 | memory in create_table_impl() and will not be put into the on-disk DD | ||
| 17507 | and DD Object Cache. | ||
| 17508 | |||
| 17509 | We become responsible for destroying this dd::Table object (for | ||
| 17510 | temporary tables until we pass its ownership to the TABLE_SHARE). | ||
| 17511 | */ | ||
| 17512 | 87519 | std::unique_ptr<dd::Table> non_dd_table_def; | |
| 17513 | |||
| 17514 | { | ||
| 17515 | 88126 | Disable_binlog_guard binlog_guard(thd); | |
| 17516 | /* Prevent intermediate commits to invoke commit order */ | ||
| 17517 | Implicit_substatement_state_guard substatement_guard( | ||
| 17518 | thd, enum_implicit_substatement_guard_mode :: | ||
| 17519 |
1/2✓ Branch 0 taken 88126 times.
✗ Branch 1 not taken.
|
88126 | DISABLE_GTID_AND_SPCO_IF_SPCO_ACTIVE); |
| 17520 |
1/2✓ Branch 0 taken 88126 times.
✗ Branch 1 not taken.
|
88126 | error = create_table_impl( |
| 17521 | thd, *new_schema, alter_ctx.new_db, alter_ctx.tmp_name, | ||
| 17522 | alter_ctx.table_name, alter_ctx.get_tmp_path(), create_info, alter_info, | ||
| 17523 | true, 0, true, true, | ||
| 17524 | /* | ||
| 17525 | If target SE supports atomic DDL do not store | ||
| 17526 | new table version in on-disk DD. | ||
| 17527 | It is not required to rollback statement in | ||
| 17528 | case of error and allows to keep correct names | ||
| 17529 | for pre-existing foreign keys in the dd::Table | ||
| 17530 | object for new table version. | ||
| 17531 | */ | ||
| 17532 | 88126 | (new_db_type->flags & HTON_SUPPORTS_ATOMIC_DDL), nullptr, &key_info, | |
| 17533 | &key_count, keys_onoff, &fk_key_info, &fk_key_count, alter_ctx.fk_info, | ||
| 17534 | alter_ctx.fk_count, old_table_def, | ||
| 17535 | alter_ctx.fk_max_generated_name_number, &non_dd_table_def, nullptr); | ||
| 17536 | 88126 | } | |
| 17537 | |||
| 17538 |
2/2✓ Branch 0 taken 8983 times.
✓ Branch 1 taken 79143 times.
|
88126 | if (error) { |
| 17539 | /* | ||
| 17540 | Play it safe, rollback possible changes to the data-dictionary, | ||
| 17541 | so failed mysql_alter_table()/mysql_recreate_table() do not | ||
| 17542 | require rollback in the caller. Also do full rollback in unlikely | ||
| 17543 | case we have THD::transaction_rollback_request. | ||
| 17544 | */ | ||
| 17545 |
1/2✓ Branch 0 taken 8983 times.
✗ Branch 1 not taken.
|
8983 | trans_rollback_stmt(thd); |
| 17546 |
1/2✓ Branch 0 taken 8983 times.
✗ Branch 1 not taken.
|
8983 | trans_rollback(thd); |
| 17547 | 8983 | return true; | |
| 17548 | } | ||
| 17549 | |||
| 17550 | /* | ||
| 17551 | Atomic replacement of the table is possible only if both old and new | ||
| 17552 | storage engines support DDL atomicity. | ||
| 17553 | */ | ||
| 17554 |
2/2✓ Branch 0 taken 62952 times.
✓ Branch 1 taken 16191 times.
|
142095 | bool atomic_replace = (new_db_type->flags & HTON_SUPPORTS_ATOMIC_DDL) && |
| 17555 |
2/2✓ Branch 0 taken 62257 times.
✓ Branch 1 taken 695 times.
|
62952 | (old_db_type->flags & HTON_SUPPORTS_ATOMIC_DDL); |
| 17556 | |||
| 17557 | /* Remember that we have not created table in storage engine yet. */ | ||
| 17558 | 79143 | bool no_ha_table = true; | |
| 17559 | |||
| 17560 | /* Indicates special case when we do ALTER TABLE which is really no-op. */ | ||
| 17561 | 79143 | bool is_noop = false; | |
| 17562 | |||
| 17563 | /* | ||
| 17564 | Indicates special case involving non-atomic ALTER TABLE which adds | ||
| 17565 | foreign keys and then fails at the late stage. Such ALTER TABLE still | ||
| 17566 | requires FK parent invalidation even despite of error. | ||
| 17567 | */ | ||
| 17568 | 79143 | bool invalidate_fk_parents_on_error = false; | |
| 17569 | |||
| 17570 | 79143 | dd::Encrypt_result old_er{false, false}; | |
| 17571 | 79143 | dd::Encrypt_result new_er{false, false}; | |
| 17572 | |||
| 17573 | /* | ||
| 17574 | If we are ALTERing non-temporary table in SE not supporting atomic DDL | ||
| 17575 | we don't have dd::Table object describing new version of table yet. | ||
| 17576 | Retrieve it now. | ||
| 17577 | */ | ||
| 17578 | 79143 | dd::Table *table_def = non_dd_table_def.get(); | |
| 17579 |
2/2✓ Branch 0 taken 16095 times.
✓ Branch 1 taken 63048 times.
|
79143 | if (!table_def) { |
| 17580 |
4/8✓ Branch 0 taken 16095 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16095 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 16095 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 16095 times.
|
16095 | if (thd->dd_client()->acquire_for_modification( |
| 17581 | alter_ctx.new_db, alter_ctx.tmp_name, &table_def)) | ||
| 17582 | ✗ | goto err_new_table_cleanup; | |
| 17583 | |||
| 17584 |
1/2✓ Branch 0 taken 16095 times.
✗ Branch 1 not taken.
|
16095 | set_check_constraints_alter_mode(table_def, alter_info); |
| 17585 | |||
| 17586 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16095 times.
|
16095 | assert(table_def); |
| 17587 | } | ||
| 17588 | |||
| 17589 |
2/2✓ Branch 0 taken 77992 times.
✓ Branch 1 taken 1151 times.
|
79143 | if (!is_tmp_table) { |
| 17590 | // Check for usage of prefix key index in PARTITION BY KEY() function. | ||
| 17591 |
1/2✓ Branch 0 taken 77992 times.
✗ Branch 1 not taken.
|
77992 | dd::warn_on_deprecated_prefix_key_partition( |
| 17592 | thd, alter_ctx.db, alter_ctx.table_name, table_def, false); | ||
| 17593 | } | ||
| 17594 | |||
| 17595 |
2/4✓ Branch 0 taken 79143 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 79143 times.
|
79143 | if (remove_secondary_engine(thd, *table_list, *create_info, old_table_def)) |
| 17596 | ✗ | goto err_new_table_cleanup; | |
| 17597 | |||
| 17598 | // If we are changing the tablespace or the table encryption type. | ||
| 17599 |
4/4✓ Branch 0 taken 77992 times.
✓ Branch 1 taken 1151 times.
✓ Branch 2 taken 14420 times.
✓ Branch 3 taken 64723 times.
|
157135 | if (old_table_def && |
| 17600 |
2/2✓ Branch 0 taken 72834 times.
✓ Branch 1 taken 5158 times.
|
77992 | (create_info->used_fields & HA_CREATE_USED_TABLESPACE || |
| 17601 |
2/2✓ Branch 0 taken 68700 times.
✓ Branch 1 taken 4134 times.
|
72834 | create_info->used_fields & HA_CREATE_USED_ENCRYPT || |
| 17602 |
4/4✓ Branch 0 taken 63671 times.
✓ Branch 1 taken 5029 times.
✓ Branch 2 taken 99 times.
✓ Branch 3 taken 63572 times.
|
132371 | create_info->used_fields & HA_CREATE_USED_AUTOEXTEND_SIZE || |
| 17603 | 63671 | alter_ctx.is_database_changed())) { | |
| 17604 | 14420 | bool source_is_general_tablespace{false}; | |
| 17605 | 14420 | bool source_encrytion_type{false}; | |
| 17606 | 14420 | bool destination_is_general_tablespace{false}; | |
| 17607 | 14420 | bool destination_encrytion_type{false}; | |
| 17608 | |||
| 17609 | // Determine source tablespace type and encryption type. | ||
| 17610 |
1/2✓ Branch 0 taken 14420 times.
✗ Branch 1 not taken.
|
14420 | old_er = dd::is_tablespace_encrypted(thd, *old_table_def, |
| 17611 | &source_is_general_tablespace); | ||
| 17612 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14420 times.
|
14420 | if (old_er.error) { |
| 17613 | 61 | goto err_new_table_cleanup; | |
| 17614 | } | ||
| 17615 | 14420 | source_encrytion_type = old_er.value; | |
| 17616 |
2/2✓ Branch 0 taken 9315 times.
✓ Branch 1 taken 5105 times.
|
23735 | if (!source_is_general_tablespace && |
| 17617 |
9/14✓ Branch 0 taken 9315 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9315 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9315 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 9297 times.
✓ Branch 7 taken 18 times.
✓ Branch 8 taken 9315 times.
✓ Branch 9 taken 5105 times.
✓ Branch 10 taken 9297 times.
✓ Branch 11 taken 5123 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
|
23735 | old_table_def->options().exists("encrypt_type")) { |
| 17618 | 9297 | dd::String_type et; | |
| 17619 |
3/6✓ Branch 0 taken 9297 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9297 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9297 times.
✗ Branch 5 not taken.
|
9297 | (void)old_table_def->options().get("encrypt_type", &et); |
| 17620 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9297 times.
|
9297 | assert(et.empty() == false); |
| 17621 |
1/2✓ Branch 0 taken 9297 times.
✗ Branch 1 not taken.
|
9297 | source_encrytion_type = is_encrypted(et); |
| 17622 | 9297 | } | |
| 17623 | |||
| 17624 | // Determine destination tablespace type and encryption type. | ||
| 17625 |
1/2✓ Branch 0 taken 14420 times.
✗ Branch 1 not taken.
|
14420 | new_er = dd::is_tablespace_encrypted(thd, *table_def, |
| 17626 | &destination_is_general_tablespace); | ||
| 17627 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14420 times.
|
14420 | if (new_er.error) { |
| 17628 | ✗ | goto err_new_table_cleanup; | |
| 17629 | } | ||
| 17630 | 14420 | destination_encrytion_type = new_er.value; | |
| 17631 |
2/2✓ Branch 0 taken 7521 times.
✓ Branch 1 taken 6899 times.
|
21941 | if (!destination_is_general_tablespace && |
| 17632 |
9/14✓ Branch 0 taken 7521 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7521 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7521 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 7505 times.
✓ Branch 7 taken 16 times.
✓ Branch 8 taken 7521 times.
✓ Branch 9 taken 6899 times.
✓ Branch 10 taken 7505 times.
✓ Branch 11 taken 6915 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
|
21941 | table_def->options().exists("encrypt_type")) { |
| 17633 | 7505 | dd::String_type et; | |
| 17634 |
3/6✓ Branch 0 taken 7505 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7505 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7505 times.
✗ Branch 5 not taken.
|
7505 | (void)table_def->options().get("encrypt_type", &et); |
| 17635 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7505 times.
|
7505 | assert(et.empty() == false); |
| 17636 |
1/2✓ Branch 0 taken 7505 times.
✗ Branch 1 not taken.
|
7505 | destination_encrytion_type = is_encrypted(et); |
| 17637 | 7505 | } | |
| 17638 | |||
| 17639 | /* | ||
| 17640 | Disallow converting a general tablespace to a file-per-table | ||
| 17641 | tablespace without a explicit ENCRYPTION clause. | ||
| 17642 | */ | ||
| 17643 |
4/4✓ Branch 0 taken 5105 times.
✓ Branch 1 taken 9315 times.
✓ Branch 2 taken 331 times.
✓ Branch 3 taken 4774 times.
|
14420 | if (source_is_general_tablespace && source_encrytion_type == true && |
| 17644 |
2/2✓ Branch 0 taken 89 times.
✓ Branch 1 taken 242 times.
|
331 | !destination_is_general_tablespace && |
| 17645 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 83 times.
|
89 | !(create_info->used_fields & HA_CREATE_USED_ENCRYPT)) { |
| 17646 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | my_error(ER_TARGET_TABLESPACE_UNENCRYPTED, MYF(0)); |
| 17647 | 6 | goto err_new_table_cleanup; | |
| 17648 | } | ||
| 17649 | |||
| 17650 | /* | ||
| 17651 | Disallow moving encrypted table (using general or file-per-table | ||
| 17652 | tablespace) to a unencrypted general tablespace. | ||
| 17653 | */ | ||
| 17654 |
4/4✓ Branch 0 taken 624 times.
✓ Branch 1 taken 13790 times.
✓ Branch 2 taken 305 times.
✓ Branch 3 taken 319 times.
|
14414 | if (source_encrytion_type && destination_is_general_tablespace && |
| 17655 |
2/2✓ Branch 0 taken 55 times.
✓ Branch 1 taken 250 times.
|
305 | !destination_encrytion_type) { |
| 17656 |
1/2✓ Branch 0 taken 55 times.
✗ Branch 1 not taken.
|
55 | my_error(ER_TARGET_TABLESPACE_UNENCRYPTED, MYF(0)); |
| 17657 | 55 | goto err_new_table_cleanup; | |
| 17658 | } | ||
| 17659 | |||
| 17660 | /* | ||
| 17661 | Check table encryption privilege, if table encryption type differ | ||
| 17662 | from schema encryption type. | ||
| 17663 | */ | ||
| 17664 |
3/4✓ Branch 0 taken 14359 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 643 times.
✓ Branch 3 taken 13716 times.
|
14359 | if (new_schema->default_encryption() != destination_encrytion_type) { |
| 17665 | // Ignore privilege check and show warning if database is same and | ||
| 17666 | // table encryption type is not changed. | ||
| 17667 |
4/4✓ Branch 0 taken 595 times.
✓ Branch 1 taken 48 times.
✓ Branch 2 taken 312 times.
✓ Branch 3 taken 283 times.
|
643 | bool show_warning = !alter_ctx.is_database_changed() && |
| 17668 | 643 | source_encrytion_type == destination_encrytion_type; | |
| 17669 | |||
| 17670 |
4/4✓ Branch 0 taken 331 times.
✓ Branch 1 taken 312 times.
✓ Branch 2 taken 112 times.
✓ Branch 3 taken 219 times.
|
643 | if (!show_warning && opt_table_encryption_privilege_check) { |
| 17671 |
3/4✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 54 times.
✓ Branch 3 taken 58 times.
|
112 | if (check_table_encryption_admin_access(thd)) { |
| 17672 |
1/2✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
|
54 | my_error(ER_CANNOT_SET_TABLE_ENCRYPTION, MYF(0)); |
| 17673 | 54 | return true; | |
| 17674 | } | ||
| 17675 |
5/6✓ Branch 0 taken 531 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 76 times.
✓ Branch 3 taken 455 times.
✓ Branch 4 taken 76 times.
✓ Branch 5 taken 455 times.
|
607 | } else if (new_schema->default_encryption() && |
| 17676 |
1/2✓ Branch 0 taken 76 times.
✗ Branch 1 not taken.
|
76 | !destination_encrytion_type) { |
| 17677 |
2/4✓ Branch 0 taken 76 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 76 times.
✗ Branch 3 not taken.
|
76 | push_warning(thd, Sql_condition::SL_WARNING, |
| 17678 | WARN_UNENCRYPTED_TABLE_IN_ENCRYPTED_DB, | ||
| 17679 | ER_THD(thd, WARN_UNENCRYPTED_TABLE_IN_ENCRYPTED_DB)); | ||
| 17680 | } | ||
| 17681 | } | ||
| 17682 | } | ||
| 17683 | |||
| 17684 |
2/2✓ Branch 0 taken 77877 times.
✓ Branch 1 taken 1151 times.
|
79028 | if (old_table_def) { |
| 17685 |
3/4✓ Branch 0 taken 77877 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1325 times.
✓ Branch 3 taken 76552 times.
|
77877 | if (is_checked_for_upgrade(*old_table_def)) { |
| 17686 |
3/16✓ Branch 0 taken 1325 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1325 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1325 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
|
1325 | DBUG_PRINT("admin", ("Transfering upgrade mark " |
| 17687 | "from Table %s (%llu) to Table %s (%llu)", | ||
| 17688 | old_table_def->name().c_str(), old_table_def->id(), | ||
| 17689 | table_def->name().c_str(), table_def->id())); | ||
| 17690 |
1/2✓ Branch 0 taken 1325 times.
✗ Branch 1 not taken.
|
1325 | table_def->mark_as_checked_for_upgrade(); |
| 17691 | } | ||
| 17692 | } | ||
| 17693 | |||
| 17694 | /* | ||
| 17695 | Check if new table definition is compatible with foreign keys | ||
| 17696 | on other tales which reference this one. We want to do this | ||
| 17697 | before starting potentially expensive main phases of COPYing | ||
| 17698 | or INPLACE ALTER TABLE. | ||
| 17699 | */ | ||
| 17700 |
2/2✓ Branch 0 taken 77877 times.
✓ Branch 1 taken 1151 times.
|
79028 | if (!is_tmp_table) { |
| 17701 |
2/2✓ Branch 0 taken 815 times.
✓ Branch 1 taken 77062 times.
|
77877 | if (new_db_type != old_db_type) { |
| 17702 | /* | ||
| 17703 | By changing table's storage engine we might be introducing parent | ||
| 17704 | table for previously orphan foreign keys in the new SE. We need | ||
| 17705 | to lock child tables of such orphan foreign keys. OTOH it is safe | ||
| 17706 | to assume that if SE is changed table can't be parent in any | ||
| 17707 | foreign keys in old SE. | ||
| 17708 | |||
| 17709 | We assume that ALTER TABLE which combines change of SE and renaming | ||
| 17710 | of table is executed by changing SE first and then performing rename | ||
| 17711 | (this is closer to ALTER TABLE real implementation). So such ALTER | ||
| 17712 | TABLEs need to pick up orphan foreign keys associated with old table | ||
| 17713 | names as well. Thus we use old table name in the below check. | ||
| 17714 | */ | ||
| 17715 |
2/4✓ Branch 0 taken 815 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 815 times.
|
815 | assert(old_table_def->foreign_key_parents().size() == 0); |
| 17716 | |||
| 17717 |
3/4✓ Branch 0 taken 815 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 811 times.
|
815 | if (check_fk_children_after_parent_def_change( |
| 17718 | thd, table_list->db, table_list->table_name, nullptr, nullptr, | ||
| 17719 | new_db_type, table_def)) | ||
| 17720 | 4 | goto err_new_table_cleanup; | |
| 17721 | } else { | ||
| 17722 |
3/4✓ Branch 0 taken 77062 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 77052 times.
|
77062 | if (check_fk_children_after_parent_def_change( |
| 17723 | thd, table_list->db, table_list->table_name, new_db_type, | ||
| 17724 | old_table_def, table_def, alter_info)) | ||
| 17725 | 10 | goto err_new_table_cleanup; | |
| 17726 | } | ||
| 17727 | |||
| 17728 |
4/4✓ Branch 0 taken 278 times.
✓ Branch 1 taken 77585 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 77861 times.
|
78141 | if (alter_ctx.is_table_renamed() && |
| 17729 |
3/4✓ Branch 0 taken 278 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 276 times.
|
278 | check_fk_children_after_parent_def_change( |
| 17730 | thd, alter_ctx.new_db, alter_ctx.new_alias, table_list->db, | ||
| 17731 | table_list->table_name, new_db_type, table_def)) | ||
| 17732 | 2 | goto err_new_table_cleanup; | |
| 17733 | } | ||
| 17734 | |||
| 17735 |
2/2✓ Branch 0 taken 74915 times.
✓ Branch 1 taken 4097 times.
|
79012 | if (alter_info->requested_algorithm != |
| 17736 | Alter_info::ALTER_TABLE_ALGORITHM_COPY) { | ||
| 17737 | Alter_inplace_info ha_alter_info(create_info, alter_info, | ||
| 17738 | 74915 | alter_ctx.error_if_not_empty, key_info, | |
| 17739 | 74915 | key_count, thd->work_part_info); | |
| 17740 | 74915 | TABLE *altered_table = nullptr; | |
| 17741 | 74915 | bool use_inplace = true; | |
| 17742 | |||
| 17743 | /* Fill the Alter_inplace_info structure. */ | ||
| 17744 |
3/4✓ Branch 0 taken 74915 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 74914 times.
|
74915 | if (fill_alter_inplace_info(thd, table, &ha_alter_info)) |
| 17745 | 1 | goto err_new_table_cleanup; | |
| 17746 | |||
| 17747 |
2/8✓ Branch 0 taken 74914 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 74914 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
74914 | DBUG_EXECUTE_IF("innodb_index_drop_count_zero", { |
| 17748 | if (ha_alter_info.index_drop_count) { | ||
| 17749 | my_error(ER_ALTER_OPERATION_NOT_SUPPORTED, MYF(0), "Index rebuild", | ||
| 17750 | "Without rebuild"); | ||
| 17751 | return true; | ||
| 17752 | } | ||
| 17753 | };); | ||
| 17754 | |||
| 17755 |
2/8✓ Branch 0 taken 74914 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 74914 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
74914 | DBUG_EXECUTE_IF("innodb_index_drop_count_one", { |
| 17756 | if (ha_alter_info.index_drop_count != 1) { | ||
| 17757 | my_error(ER_ALTER_OPERATION_NOT_SUPPORTED, MYF(0), "Index change", | ||
| 17758 | "Index rebuild"); | ||
| 17759 | return true; | ||
| 17760 | } | ||
| 17761 | };); | ||
| 17762 | |||
| 17763 | // We assume that the table is non-temporary. | ||
| 17764 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 74914 times.
|
74914 | assert(!table->s->tmp_table); |
| 17765 | |||
| 17766 |
3/4✓ Branch 0 taken 74914 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
✓ Branch 3 taken 74894 times.
|
74914 | if (!(altered_table = open_table_uncached( |
| 17767 | thd, alter_ctx.get_tmp_path(), alter_ctx.new_db, | ||
| 17768 | alter_ctx.tmp_name, true, false, *table_def))) | ||
| 17769 | 20 | goto err_new_table_cleanup; | |
| 17770 | |||
| 17771 |
3/4✓ Branch 0 taken 72919 times.
✓ Branch 1 taken 1975 times.
✓ Branch 2 taken 72919 times.
✗ Branch 3 not taken.
|
74894 | DEBUG_SYNC(thd, "after_open_altered_table"); |
| 17772 | |||
| 17773 | /* Set markers for fields in TABLE object for altered table. */ | ||
| 17774 | 74894 | update_altered_table(ha_alter_info, altered_table); | |
| 17775 | |||
| 17776 | /* | ||
| 17777 | Updating field definitions in 'altered_table' with zip_dict_name values | ||
| 17778 | from 'ha_alter_info.alter_info->create_list' | ||
| 17779 | */ | ||
| 17780 |
2/4✓ Branch 0 taken 74894 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 74894 times.
✗ Branch 3 not taken.
|
74894 | if (ha_alter_info.alter_info != 0 && altered_table != 0) { |
| 17781 | 74894 | altered_table->update_compressed_columns_info( | |
| 17782 |
1/2✓ Branch 0 taken 74894 times.
✗ Branch 1 not taken.
|
74894 | ha_alter_info.alter_info->create_list); |
| 17783 | } | ||
| 17784 | |||
| 17785 | /* | ||
| 17786 | Mark all columns in 'altered_table' as used to allow usage | ||
| 17787 | of its record[0] buffer and Field objects during in-place | ||
| 17788 | ALTER TABLE. | ||
| 17789 | */ | ||
| 17790 | 74894 | altered_table->column_bitmaps_set_no_signal(&altered_table->s->all_set, | |
| 17791 | 74894 | &altered_table->s->all_set); | |
| 17792 | |||
| 17793 |
1/2✓ Branch 0 taken 74894 times.
✗ Branch 1 not taken.
|
74894 | set_column_static_defaults(altered_table, alter_info->create_list); |
| 17794 | |||
| 17795 |
2/2✓ Branch 0 taken 234 times.
✓ Branch 1 taken 74660 times.
|
74894 | if (ha_alter_info.handler_flags == 0) { |
| 17796 | /* | ||
| 17797 | No-op ALTER, no need to call handler API functions. | ||
| 17798 | |||
| 17799 | If this code path is entered for an ALTER statement that | ||
| 17800 | should not be a real no-op, new handler flags should be added | ||
| 17801 | and fill_alter_inplace_info() adjusted. | ||
| 17802 | |||
| 17803 | Note that we can end up here if an ALTER statement has clauses | ||
| 17804 | that cancel each other out (e.g. ADD/DROP identically index). | ||
| 17805 | |||
| 17806 | Also note that we ignore the LOCK clause here. | ||
| 17807 | */ | ||
| 17808 |
1/2✓ Branch 0 taken 234 times.
✗ Branch 1 not taken.
|
234 | close_temporary_table(thd, altered_table, true, false); |
| 17809 | |||
| 17810 |
2/2✓ Branch 0 taken 86 times.
✓ Branch 1 taken 148 times.
|
234 | if (!(create_info->db_type->flags & HTON_SUPPORTS_ATOMIC_DDL)) { |
| 17811 | // Delete temporary table object from data dictionary. | ||
| 17812 |
1/2✓ Branch 0 taken 86 times.
✗ Branch 1 not taken.
|
86 | bool result = dd::drop_table(thd, alter_ctx.new_db, alter_ctx.tmp_name, |
| 17813 | *table_def); | ||
| 17814 |
1/2✓ Branch 0 taken 86 times.
✗ Branch 1 not taken.
|
86 | (void)trans_intermediate_ddl_commit(thd, result); |
| 17815 | } | ||
| 17816 | |||
| 17817 | 234 | is_noop = true; | |
| 17818 | 234 | goto end_inplace_noop; | |
| 17819 | } | ||
| 17820 | |||
| 17821 | // Ask storage engine whether to use copy or in-place | ||
| 17822 | enum_alter_inplace_result inplace_supported = | ||
| 17823 |
1/2✓ Branch 0 taken 74660 times.
✗ Branch 1 not taken.
|
74660 | table->file->check_if_supported_inplace_alter(altered_table, |
| 17824 | &ha_alter_info); | ||
| 17825 | |||
| 17826 | // If INSTANT was requested but it is not supported, report error. | ||
| 17827 |
2/2✓ Branch 0 taken 1007 times.
✓ Branch 1 taken 73653 times.
|
74660 | if (alter_info->requested_algorithm == |
| 17828 |
2/2✓ Branch 0 taken 58 times.
✓ Branch 1 taken 949 times.
|
1007 | Alter_info::ALTER_TABLE_ALGORITHM_INSTANT && |
| 17829 |
2/2✓ Branch 0 taken 48 times.
✓ Branch 1 taken 10 times.
|
58 | inplace_supported != HA_ALTER_INPLACE_INSTANT && |
| 17830 | inplace_supported != HA_ALTER_ERROR) { | ||
| 17831 |
1/2✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
|
48 | ha_alter_info.report_unsupported_error("ALGORITHM=INSTANT", |
| 17832 | "ALGORITHM=COPY/INPLACE"); | ||
| 17833 |
1/2✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
|
48 | close_temporary_table(thd, altered_table, true, false); |
| 17834 | 48 | goto err_new_table_cleanup; | |
| 17835 | } | ||
| 17836 | |||
| 17837 |
5/5✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1955 times.
✓ Branch 2 taken 55820 times.
✓ Branch 3 taken 16809 times.
✓ Branch 4 taken 22 times.
|
74612 | switch (inplace_supported) { |
| 17838 | 6 | case HA_ALTER_INPLACE_EXCLUSIVE_LOCK: | |
| 17839 | // If SHARED lock and no particular algorithm was requested, use COPY. | ||
| 17840 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if (alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_SHARED && |
| 17841 | ✗ | alter_info->requested_algorithm == | |
| 17842 | Alter_info::ALTER_TABLE_ALGORITHM_DEFAULT) { | ||
| 17843 | ✗ | use_inplace = false; | |
| 17844 | } | ||
| 17845 | // Otherwise, if weaker lock was requested, report error. | ||
| 17846 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | else if (alter_info->requested_lock == |
| 17847 | 6 | Alter_info::ALTER_TABLE_LOCK_NONE || | |
| 17848 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | alter_info->requested_lock == |
| 17849 | Alter_info::ALTER_TABLE_LOCK_SHARED) { | ||
| 17850 | ✗ | ha_alter_info.report_unsupported_error("LOCK=NONE/SHARED", | |
| 17851 | "LOCK=EXCLUSIVE"); | ||
| 17852 | ✗ | close_temporary_table(thd, altered_table, true, false); | |
| 17853 | ✗ | goto err_new_table_cleanup; | |
| 17854 | } | ||
| 17855 | 6 | break; | |
| 17856 | 1955 | case HA_ALTER_INPLACE_SHARED_LOCK_AFTER_PREPARE: | |
| 17857 | case HA_ALTER_INPLACE_SHARED_LOCK: | ||
| 17858 | // If weaker lock was requested, report error. | ||
| 17859 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 1944 times.
|
1955 | if (alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_NONE) { |
| 17860 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
11 | ha_alter_info.report_unsupported_error("LOCK=NONE", "LOCK=SHARED"); |
| 17861 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
11 | close_temporary_table(thd, altered_table, true, false); |
| 17862 | 11 | goto err_new_table_cleanup; | |
| 17863 | } | ||
| 17864 | 1944 | break; | |
| 17865 | 55820 | case HA_ALTER_INPLACE_NO_LOCK_AFTER_PREPARE: | |
| 17866 | case HA_ALTER_INPLACE_NO_LOCK: | ||
| 17867 | case HA_ALTER_INPLACE_INSTANT: | ||
| 17868 | /* | ||
| 17869 | Note that any instant operation is also in fact in-place operation. | ||
| 17870 | |||
| 17871 | It is totally safe to execute operation using instant algorithm if it | ||
| 17872 | has no drawbacks as compared to in-place algorithm even if user | ||
| 17873 | explicitly asked for ALGORITHM=INPLACE. Doing so, also allows to | ||
| 17874 | keep code in engines which support only limited subset of in-place | ||
| 17875 | ALTER TABLE operations as instant metadata only changes simple. | ||
| 17876 | |||
| 17877 | If instant algorithm has some downsides to in-place algorithm and user | ||
| 17878 | explicitly asks for ALGORITHM=INPLACE it is responsibility of storage | ||
| 17879 | engine to fallback to in-place algorithm execution by returning | ||
| 17880 | HA_ALTER_INPLACE_NO_LOCK or HA_ALTER_INPLACE_NO_LOCK_AFTER_PREPARE. | ||
| 17881 | */ | ||
| 17882 | 55820 | break; | |
| 17883 | 16809 | case HA_ALTER_INPLACE_NOT_SUPPORTED: | |
| 17884 | // If INPLACE was requested, report error. | ||
| 17885 |
2/2✓ Branch 0 taken 159 times.
✓ Branch 1 taken 16650 times.
|
16809 | if (alter_info->requested_algorithm == |
| 17886 | Alter_info::ALTER_TABLE_ALGORITHM_INPLACE) { | ||
| 17887 |
1/2✓ Branch 0 taken 159 times.
✗ Branch 1 not taken.
|
159 | ha_alter_info.report_unsupported_error("ALGORITHM=INPLACE", |
| 17888 | "ALGORITHM=COPY"); | ||
| 17889 |
1/2✓ Branch 0 taken 159 times.
✗ Branch 1 not taken.
|
159 | close_temporary_table(thd, altered_table, true, false); |
| 17890 | 159 | goto err_new_table_cleanup; | |
| 17891 | } | ||
| 17892 | // COPY with LOCK=NONE is not supported, no point in trying. | ||
| 17893 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 16647 times.
|
16650 | if (alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_NONE) { |
| 17894 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | ha_alter_info.report_unsupported_error("LOCK=NONE", "LOCK=SHARED"); |
| 17895 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | close_temporary_table(thd, altered_table, true, false); |
| 17896 | 3 | goto err_new_table_cleanup; | |
| 17897 | } | ||
| 17898 | // Otherwise use COPY | ||
| 17899 | 16647 | use_inplace = false; | |
| 17900 | 16647 | break; | |
| 17901 | 22 | case HA_ALTER_ERROR: | |
| 17902 | default: | ||
| 17903 |
1/2✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
|
22 | close_temporary_table(thd, altered_table, true, false); |
| 17904 | 22 | goto err_new_table_cleanup; | |
| 17905 | } | ||
| 17906 | |||
| 17907 |
2/2✓ Branch 0 taken 57770 times.
✓ Branch 1 taken 16647 times.
|
74417 | if (use_inplace) { |
| 17908 |
3/4✓ Branch 0 taken 57283 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 571 times.
✓ Branch 3 taken 56712 times.
|
57770 | if (mysql_inplace_alter_table(thd, *schema, *new_schema, old_table_def, |
| 17909 | table_def, table_list, table, altered_table, | ||
| 17910 | &ha_alter_info, inplace_supported, | ||
| 17911 | &alter_ctx, columns, fk_key_info, | ||
| 17912 | fk_key_count, &fk_invalidator)) { | ||
| 17913 | 571 | return true; | |
| 17914 | } | ||
| 17915 | |||
| 17916 | 56712 | const dd::Table *new_table_def = nullptr; | |
| 17917 |
4/8✓ Branch 0 taken 56712 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 56712 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 56712 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 56712 times.
|
56712 | if (thd->dd_client()->acquire(alter_ctx.new_db, alter_ctx.new_name, |
| 17918 | &new_table_def)) { | ||
| 17919 | ✗ | DBUG_LOG("zip_dict", | |
| 17920 | "Acquiring dictionary table object failed " | ||
| 17921 | " for query " | ||
| 17922 | << thd->query().str << " table_db: " << alter_ctx.new_db | ||
| 17923 | << " table_name: " << alter_ctx.new_name); | ||
| 17924 | ✗ | return true; | |
| 17925 | } | ||
| 17926 | /* New table is successfully created, check if any columns have | ||
| 17927 | compression dictionary and add entry for them in | ||
| 17928 | mysql.compression_dictionary_cols table */ | ||
| 17929 |
2/4✓ Branch 0 taken 56712 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 56712 times.
|
56712 | if (compression_dict::cols_table_insert(thd, *new_table_def)) return true; |
| 17930 | |||
| 17931 | 56712 | goto end_inplace; | |
| 17932 | } else { | ||
| 17933 |
1/2✓ Branch 0 taken 16647 times.
✗ Branch 1 not taken.
|
16647 | close_temporary_table(thd, altered_table, true, false); |
| 17934 | } | ||
| 17935 |
5/5✓ Branch 0 taken 16647 times.
✓ Branch 1 taken 264 times.
✓ Branch 2 taken 571 times.
✓ Branch 3 taken 234 times.
✓ Branch 4 taken 56712 times.
|
74428 | } |
| 17936 | |||
| 17937 | /* ALTER TABLE using copy algorithm. */ | ||
| 17938 | |||
| 17939 | /* Check if ALTER TABLE is compatible with foreign key definitions. */ | ||
| 17940 |
3/4✓ Branch 0 taken 20744 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 20742 times.
|
20744 | if (fk_check_copy_alter_table(thd, table_list, old_table_def, alter_info)) |
| 17941 | 2 | goto err_new_table_cleanup; | |
| 17942 | |||
| 17943 |
2/2✓ Branch 0 taken 19591 times.
✓ Branch 1 taken 1151 times.
|
20742 | if (!table->s->tmp_table) { |
| 17944 |
1/2✓ Branch 0 taken 19591 times.
✗ Branch 1 not taken.
|
19591 | MDL_request_list mdl_requests; |
| 17945 | |||
| 17946 | // COPY algorithm doesn't work with concurrent writes. | ||
| 17947 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 19584 times.
|
19591 | if (alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_NONE) { |
| 17948 |
2/4✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
|
7 | my_error(ER_ALTER_OPERATION_NOT_SUPPORTED_REASON, MYF(0), "LOCK=NONE", |
| 17949 | ER_THD(thd, ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_COPY), | ||
| 17950 | "LOCK=SHARED"); | ||
| 17951 | 34 | goto err_new_table_cleanup; | |
| 17952 | } | ||
| 17953 | |||
| 17954 | // If EXCLUSIVE lock is requested, upgrade already. | ||
| 17955 |
3/4✓ Branch 0 taken 12 times.
✓ Branch 1 taken 19572 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 19584 times.
|
19596 | if (alter_info->requested_lock == Alter_info::ALTER_TABLE_LOCK_EXCLUSIVE && |
| 17956 |
2/4✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
|
12 | wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN)) |
| 17957 | ✗ | goto err_new_table_cleanup; | |
| 17958 | |||
| 17959 | /* | ||
| 17960 | Otherwise upgrade to SHARED_NO_WRITE. | ||
| 17961 | Note that under LOCK TABLES, we will already have SHARED_NO_READ_WRITE. | ||
| 17962 | */ | ||
| 17963 |
4/4✓ Branch 0 taken 19572 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 26 times.
✓ Branch 3 taken 19558 times.
|
39156 | if (alter_info->requested_lock != Alter_info::ALTER_TABLE_LOCK_EXCLUSIVE && |
| 17964 |
3/4✓ Branch 0 taken 19572 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
✓ Branch 3 taken 19546 times.
|
19572 | thd->mdl_context.upgrade_shared_lock(mdl_ticket, MDL_SHARED_NO_WRITE, |
| 17965 | thd->variables.lock_wait_timeout)) | ||
| 17966 | 26 | goto err_new_table_cleanup; | |
| 17967 | |||
| 17968 |
3/4✓ Branch 0 taken 19365 times.
✓ Branch 1 taken 193 times.
✓ Branch 2 taken 19365 times.
✗ Branch 3 not taken.
|
19558 | DEBUG_SYNC(thd, "alter_table_copy_after_lock_upgrade"); |
| 17969 | |||
| 17970 | /* | ||
| 17971 | COPY algorithm creates new table version in the new database. | ||
| 17972 | So if new database differs from old one we need to lock all | ||
| 17973 | foreign key names in new table version. If it is the same as | ||
| 17974 | the old one we need to lock only names of foreign keys added. | ||
| 17975 | |||
| 17976 | Also if table is renamed we need to acquire locks on all foreign | ||
| 17977 | key names involved (taking into account adjustment of auto-generated | ||
| 17978 | names). | ||
| 17979 | */ | ||
| 17980 |
2/2✓ Branch 0 taken 42 times.
✓ Branch 1 taken 19516 times.
|
19558 | if (alter_ctx.is_database_changed()) { |
| 17981 |
2/4✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 42 times.
|
42 | if (collect_fk_names(thd, alter_ctx.new_db, table_def, &mdl_requests)) |
| 17982 | ✗ | goto err_new_table_cleanup; | |
| 17983 | } else { | ||
| 17984 |
3/6✓ Branch 0 taken 19516 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19516 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 19516 times.
|
19516 | if (collect_fk_names_for_new_fks( |
| 17985 | thd, alter_ctx.new_db, table_list->table_name, alter_info, | ||
| 17986 | new_db_type, | ||
| 17987 | get_fk_max_generated_name_number(table_list->table_name, | ||
| 17988 | old_table_def, new_db_type), | ||
| 17989 | &mdl_requests)) | ||
| 17990 | ✗ | goto err_new_table_cleanup; | |
| 17991 | } | ||
| 17992 | |||
| 17993 |
3/4✓ Branch 0 taken 113 times.
✓ Branch 1 taken 19445 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 19558 times.
|
19671 | if (alter_ctx.is_table_renamed() && |
| 17994 |
2/4✓ Branch 0 taken 113 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 113 times.
|
113 | collect_fk_names_for_rename_table( |
| 17995 | thd, table_list->db, table_list->table_name, table_def, new_db_type, | ||
| 17996 | alter_ctx.new_db, alter_ctx.new_name, &mdl_requests)) | ||
| 17997 | ✗ | goto err_new_table_cleanup; | |
| 17998 | |||
| 17999 | /* | ||
| 18000 | Acquire SRO locks on parent tables for newly added foreign keys | ||
| 18001 | in order to prevent concurrent DML on them. | ||
| 18002 | |||
| 18003 | This is temporary workaround to the problem caused by the fact that | ||
| 18004 | InnoDB makes such foreign keys visible in its internal dictionary | ||
| 18005 | cache before ALTER TABLE commit. So such DML can result in access | ||
| 18006 | to our temporary table without prior acquisition of metadata lock | ||
| 18007 | on it (which would have blocked such access normally). As result | ||
| 18008 | our ALTER TABLE can fail due to locks acquired by these accesses. | ||
| 18009 | |||
| 18010 | Long-term the problem should be solved by adjusting InnoDB code | ||
| 18011 | to avoid making such uncommitted changes visible to other | ||
| 18012 | connections. | ||
| 18013 | */ | ||
| 18014 |
2/4✓ Branch 0 taken 19558 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 19558 times.
|
19558 | if (collect_fk_parents_for_new_fks( |
| 18015 | thd, table_list->db, table_list->table_name, alter_info, | ||
| 18016 | MDL_SHARED_READ_ONLY, nullptr, &mdl_requests, nullptr)) | ||
| 18017 | ✗ | goto err_new_table_cleanup; | |
| 18018 | |||
| 18019 |
3/4✓ Branch 0 taken 101 times.
✓ Branch 1 taken 19457 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 19558 times.
|
19659 | if (!mdl_requests.is_empty() && |
| 18020 |
2/4✓ Branch 0 taken 101 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 101 times.
|
101 | thd->mdl_context.acquire_locks(&mdl_requests, |
| 18021 | thd->variables.lock_wait_timeout)) | ||
| 18022 | ✗ | goto err_new_table_cleanup; | |
| 18023 | |||
| 18024 | /* | ||
| 18025 | Check if ALTER TABLE results in any foreign key name conflicts | ||
| 18026 | before starting potentially expensive copying operation. | ||
| 18027 | */ | ||
| 18028 |
4/10✓ Branch 0 taken 19558 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19558 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 7152 times.
✓ Branch 5 taken 12406 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
39116 | if (!dd::get_dictionary()->is_dd_table_name(table_list->db, |
| 18029 |
6/10✓ Branch 0 taken 19558 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19558 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 19558 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 19556 times.
✓ Branch 7 taken 2 times.
✓ Branch 8 taken 19558 times.
✗ Branch 9 not taken.
|
58672 | table_list->table_name) && |
| 18030 |
2/2✓ Branch 0 taken 7152 times.
✓ Branch 1 taken 12404 times.
|
19556 | (new_db_type->flags & HTON_SUPPORTS_FOREIGN_KEYS)) { |
| 18031 |
2/2✓ Branch 0 taken 41 times.
✓ Branch 1 taken 7111 times.
|
7152 | if (alter_ctx.is_database_changed()) { |
| 18032 | /* | ||
| 18033 | If new table version was created schema different from the old one | ||
| 18034 | we need to check names for both pre-existing and newly added foreign | ||
| 18035 | keys. | ||
| 18036 | */ | ||
| 18037 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
|
41 | for (FOREIGN_KEY *fk = fk_key_info; fk < fk_key_info + fk_key_count; |
| 18038 | ++fk) { | ||
| 18039 | bool exists; | ||
| 18040 | ✗ | if (thd->dd_client()->check_foreign_key_exists(*new_schema, fk->name, | |
| 18041 | &exists)) | ||
| 18042 | ✗ | goto err_new_table_cleanup; | |
| 18043 | |||
| 18044 | ✗ | if (exists) { | |
| 18045 | ✗ | my_error(ER_FK_DUP_NAME, MYF(0), fk->name); | |
| 18046 | ✗ | goto err_new_table_cleanup; | |
| 18047 | } | ||
| 18048 | } | ||
| 18049 | } else { | ||
| 18050 | /* Otherwise we can limit our check to newly added foreign keys only. */ | ||
| 18051 | 7201 | for (FOREIGN_KEY *fk = fk_key_info + alter_ctx.fk_count; | |
| 18052 |
2/2✓ Branch 0 taken 91 times.
✓ Branch 1 taken 7110 times.
|
7201 | fk < fk_key_info + fk_key_count; ++fk) { |
| 18053 | bool exists; | ||
| 18054 |
3/6✓ Branch 0 taken 91 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 91 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 91 times.
|
91 | if (thd->dd_client()->check_foreign_key_exists(*new_schema, fk->name, |
| 18055 | &exists)) | ||
| 18056 | 1 | goto err_new_table_cleanup; | |
| 18057 | |||
| 18058 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 90 times.
|
91 | if (exists) { |
| 18059 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_FK_DUP_NAME, MYF(0), fk->name); |
| 18060 | 1 | goto err_new_table_cleanup; | |
| 18061 | } | ||
| 18062 | } | ||
| 18063 | } | ||
| 18064 | |||
| 18065 |
3/4✓ Branch 0 taken 107 times.
✓ Branch 1 taken 7044 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7151 times.
|
7258 | if (alter_ctx.is_table_renamed() && |
| 18066 |
2/4✓ Branch 0 taken 107 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 107 times.
|
107 | check_fk_names_before_rename(thd, table_list, *table_def, new_db_type, |
| 18067 | *new_schema, alter_ctx)) | ||
| 18068 | ✗ | goto err_new_table_cleanup; | |
| 18069 | } | ||
| 18070 | } | ||
| 18071 | |||
| 18072 | { | ||
| 18073 |
3/4✓ Branch 0 taken 20645 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 150 times.
✓ Branch 3 taken 20495 times.
|
20708 | if (ha_create_table(thd, alter_ctx.get_tmp_path(), alter_ctx.new_db, |
| 18074 | alter_ctx.tmp_name, create_info, | ||
| 18075 | 20708 | &alter_info->create_list, false, true, table_def)) | |
| 18076 | 150 | goto err_new_table_cleanup; | |
| 18077 | |||
| 18078 | /* Mark that we have created table in storage engine. */ | ||
| 18079 | 20495 | no_ha_table = false; | |
| 18080 | |||
| 18081 |
2/2✓ Branch 0 taken 1143 times.
✓ Branch 1 taken 19352 times.
|
20495 | if (create_info->options & HA_LEX_CREATE_TMP_TABLE) { |
| 18082 |
3/6✓ Branch 0 taken 1143 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1143 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1143 times.
|
2286 | if (thd->decide_logging_format(table_list) || |
| 18083 |
2/4✓ Branch 0 taken 1143 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1143 times.
|
1143 | !open_table_uncached(thd, alter_ctx.get_tmp_path(), alter_ctx.new_db, |
| 18084 | alter_ctx.tmp_name, true, true, *table_def)) | ||
| 18085 | ✗ | goto err_new_table_cleanup; | |
| 18086 | /* in case of alter temp table send the tracker in OK packet */ | ||
| 18087 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1141 times.
|
1143 | if (thd->session_tracker.get_tracker(SESSION_STATE_CHANGE_TRACKER) |
| 18088 |
1/2✓ Branch 0 taken 1143 times.
✗ Branch 1 not taken.
|
1143 | ->is_enabled()) |
| 18089 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | thd->session_tracker.get_tracker(SESSION_STATE_CHANGE_TRACKER) |
| 18090 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | ->mark_as_changed(thd, {}); |
| 18091 | } | ||
| 18092 | |||
| 18093 | /* Open the table since we need to copy the data. */ | ||
| 18094 |
2/2✓ Branch 0 taken 1143 times.
✓ Branch 1 taken 19352 times.
|
20495 | if (table->s->tmp_table != NO_TMP_TABLE) { |
| 18095 |
1/2✓ Branch 0 taken 1143 times.
✗ Branch 1 not taken.
|
1143 | TABLE_LIST tbl(alter_ctx.new_db, alter_ctx.tmp_name, TL_READ_NO_INSERT); |
| 18096 | /* Table is in thd->temporary_tables */ | ||
| 18097 |
1/2✓ Branch 0 taken 1143 times.
✗ Branch 1 not taken.
|
1143 | (void)open_temporary_table(thd, &tbl); |
| 18098 | 1143 | new_table = tbl.table; | |
| 18099 | /* Transfer dd::Table ownership to temporary table's share. */ | ||
| 18100 | 1143 | new_table->s->tmp_table_def = non_dd_table_def.release(); | |
| 18101 | } else { | ||
| 18102 | /* table is a normal table: Create temporary table in same directory */ | ||
| 18103 | /* Open our intermediate table. */ | ||
| 18104 | new_table = | ||
| 18105 |
1/2✓ Branch 0 taken 19352 times.
✗ Branch 1 not taken.
|
19352 | open_table_uncached(thd, alter_ctx.get_tmp_path(), alter_ctx.new_db, |
| 18106 | alter_ctx.tmp_name, true, true, *table_def); | ||
| 18107 | } | ||
| 18108 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20495 times.
|
20495 | if (!new_table) goto err_new_table_cleanup; |
| 18109 | /* | ||
| 18110 | Note: In case of MERGE table, we do not attach children. We do not | ||
| 18111 | copy data for MERGE tables. Only the children have data. | ||
| 18112 | */ | ||
| 18113 | |||
| 18114 | // It's now safe to take the table level lock. | ||
| 18115 |
2/4✓ Branch 0 taken 20495 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 20495 times.
|
20495 | if (lock_tables(thd, table_list, alter_ctx.tables_opened, 0)) |
| 18116 | ✗ | goto err_new_table_cleanup; | |
| 18117 | } | ||
| 18118 | |||
| 18119 | /* | ||
| 18120 | We do not copy data for MERGE tables. Only the children have data. | ||
| 18121 | MERGE tables have HA_NO_COPY_ON_ALTER set. | ||
| 18122 | */ | ||
| 18123 |
2/2✓ Branch 0 taken 20472 times.
✓ Branch 1 taken 23 times.
|
20495 | if (!(new_table->file->ha_table_flags() & HA_NO_COPY_ON_ALTER)) { |
| 18124 | /* | ||
| 18125 | Check if we can temporarily remove secondary indexes from the table | ||
| 18126 | before copying the data and recreate them later to utilize InnoDB fast | ||
| 18127 | index creation. | ||
| 18128 | TODO: is there a better way to check for InnoDB? | ||
| 18129 | */ | ||
| 18130 | const bool optimize_keys = | ||
| 18131 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 20467 times.
|
20477 | (alter_info->delayed_key_count > 0) && |
| 18132 |
3/6✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
|
5 | !my_strcasecmp(system_charset_info, new_table->file->table_type(), |
| 18133 | "InnoDB"); | ||
| 18134 | 20472 | new_table->next_number_field = new_table->found_next_number_field; | |
| 18135 |
1/2✓ Branch 0 taken 20472 times.
✗ Branch 1 not taken.
|
20472 | THD_STAGE_INFO(thd, stage_copy_to_tmp_table); |
| 18136 |
4/6✓ Branch 0 taken 20472 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 20471 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
21445 | DBUG_EXECUTE_IF("abort_copy_table", { |
| 18137 | my_error(ER_LOCK_WAIT_TIMEOUT, MYF(0)); | ||
| 18138 | goto err_new_table_cleanup; | ||
| 18139 | }); | ||
| 18140 | |||
| 18141 | /* List of dd::Indexes (secondary non-unique) in table_def that are marked | ||
| 18142 | as hidden. These indexes are temporarily disabled */ | ||
| 18143 | 20471 | std::vector<dd::Index *> dd_disabled_sec_keys; | |
| 18144 | 20471 | bool err_remove_keys = false; | |
| 18145 | |||
| 18146 |
1/2✓ Branch 0 taken 20471 times.
✗ Branch 1 not taken.
|
20471 | new_table->file->ha_extra(HA_EXTRA_BEGIN_ALTER_COPY); |
| 18147 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 20466 times.
|
20471 | if (optimize_keys) { |
| 18148 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
10 | err_remove_keys = remove_secondary_keys( |
| 18149 | thd, create_info, new_table, alter_info, | ||
| 18150 | 5 | is_tmp_table ? table->s->tmp_table_def : old_table_def, table_def, | |
| 18151 | &dd_disabled_sec_keys); | ||
| 18152 | } | ||
| 18153 | |||
| 18154 | 40940 | bool err_copy = copy_data_between_tables( | |
| 18155 | thd, thd->m_stage_progress_psi, table, new_table, | ||
| 18156 |
1/2✓ Branch 0 taken 20469 times.
✗ Branch 1 not taken.
|
20471 | alter_info->create_list, &copied, &deleted, alter_info->keys_onoff, |
| 18157 | 20469 | &alter_ctx, optimize_keys); | |
| 18158 | |||
| 18159 | 20469 | bool err_restore_keys = false; | |
| 18160 |
3/4✓ Branch 0 taken 5 times.
✓ Branch 1 taken 20464 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
20469 | if (optimize_keys && !err_remove_keys) { |
| 18161 | // Use a clean diagnostic area so restore_secondary_keys can be executed | ||
| 18162 | // whatever the previous results | ||
| 18163 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | auto da_man = thd->is_error() |
| 18164 | ? std::make_optional<Diagnostics_area_man>(thd) | ||
| 18165 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
5 | : std::nullopt; |
| 18166 | |||
| 18167 | err_restore_keys = | ||
| 18168 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
5 | restore_secondary_keys(thd, create_info, new_table, alter_info, |
| 18169 | table_def, &dd_disabled_sec_keys); | ||
| 18170 | 4 | } | |
| 18171 | |||
| 18172 |
1/2✓ Branch 0 taken 20468 times.
✗ Branch 1 not taken.
|
20468 | new_table->file->ha_extra(HA_EXTRA_END_ALTER_COPY); |
| 18173 | |||
| 18174 |
3/4✓ Branch 0 taken 19495 times.
✓ Branch 1 taken 973 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 19495 times.
|
20468 | if (err_copy || err_restore_keys) { |
| 18175 | 973 | goto err_new_table_cleanup; | |
| 18176 | } | ||
| 18177 | |||
| 18178 |
3/4✓ Branch 0 taken 19302 times.
✓ Branch 1 taken 193 times.
✓ Branch 2 taken 19302 times.
✗ Branch 3 not taken.
|
19495 | DEBUG_SYNC(thd, "alter_after_copy_table"); |
| 18179 |
2/2✓ Branch 0 taken 19495 times.
✓ Branch 1 taken 973 times.
|
20468 | } else { |
| 18180 | /* Should be MERGE only */ | ||
| 18181 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | assert(new_table->file->ht->db_type == DB_TYPE_MRG_MYISAM); |
| 18182 |
4/4✓ Branch 0 taken 8 times.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 22 times.
|
31 | if (!table->s->tmp_table && |
| 18183 |
3/4✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 7 times.
|
8 | wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN)) |
| 18184 | 1 | goto err_new_table_cleanup; | |
| 18185 |
1/2✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
|
22 | THD_STAGE_INFO(thd, stage_manage_keys); |
| 18186 |
2/4✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 22 times.
✗ Branch 3 not taken.
|
22 | DEBUG_SYNC(thd, "alter_table_manage_keys"); |
| 18187 |
2/4✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 22 times.
✗ Branch 3 not taken.
|
22 | alter_table_manage_keys(thd, table, table->file->indexes_are_disabled(), |
| 18188 | alter_info->keys_onoff); | ||
| 18189 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
|
22 | assert(!(new_db_type->flags & HTON_SUPPORTS_ATOMIC_DDL)); |
| 18190 | |||
| 18191 | /* Prevent intermediate commits to invoke commit order */ | ||
| 18192 | Implicit_substatement_state_guard substatement_guard( | ||
| 18193 | thd, enum_implicit_substatement_guard_mode :: | ||
| 18194 |
1/2✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
|
22 | DISABLE_GTID_AND_SPCO_IF_SPCO_ACTIVE); |
| 18195 | |||
| 18196 |
5/10✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 22 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 22 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 22 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 22 times.
|
22 | if (trans_commit_stmt(thd) || trans_commit_implicit(thd)) |
| 18197 | ✗ | goto err_new_table_cleanup; | |
| 18198 |
1/2✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
|
22 | } |
| 18199 | |||
| 18200 |
2/2✓ Branch 0 taken 1141 times.
✓ Branch 1 taken 18376 times.
|
19517 | if (table->s->tmp_table != NO_TMP_TABLE) { |
| 18201 | /* Close lock if this is a transactional table */ | ||
| 18202 |
1/2✓ Branch 0 taken 1141 times.
✗ Branch 1 not taken.
|
1141 | if (thd->lock) { |
| 18203 |
2/2✓ Branch 0 taken 1140 times.
✓ Branch 1 taken 1 times.
|
1141 | if (thd->locked_tables_mode != LTM_LOCK_TABLES && |
| 18204 |
1/2✓ Branch 0 taken 1140 times.
✗ Branch 1 not taken.
|
1140 | thd->locked_tables_mode != LTM_PRELOCKED_UNDER_LOCK_TABLES) { |
| 18205 |
1/2✓ Branch 0 taken 1140 times.
✗ Branch 1 not taken.
|
1140 | mysql_unlock_tables(thd, thd->lock); |
| 18206 | 1140 | thd->lock = nullptr; | |
| 18207 | } else { | ||
| 18208 | /* | ||
| 18209 | If LOCK TABLES list is not empty and contains this table, | ||
| 18210 | unlock the table and remove the table from this list. | ||
| 18211 | */ | ||
| 18212 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | mysql_lock_remove(thd, thd->lock, table); |
| 18213 | } | ||
| 18214 | } | ||
| 18215 | /* Remove link to old table and rename the new one */ | ||
| 18216 |
1/2✓ Branch 0 taken 1141 times.
✗ Branch 1 not taken.
|
1141 | close_temporary_table(thd, table, true, true); |
| 18217 | /* Should pass the 'new_name' as we store table name in the cache */ | ||
| 18218 |
2/4✓ Branch 0 taken 1141 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1141 times.
|
1141 | if (rename_temporary_table(thd, new_table, alter_ctx.new_db, |
| 18219 | alter_ctx.new_name)) | ||
| 18220 | ✗ | goto err_new_table_cleanup; | |
| 18221 | /* | ||
| 18222 | We don't replicate alter table statement on temporary tables | ||
| 18223 | in RBR mode. | ||
| 18224 | */ | ||
| 18225 |
3/4✓ Branch 0 taken 28 times.
✓ Branch 1 taken 1113 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1141 times.
|
1169 | if (!thd->is_current_stmt_binlog_format_row() && |
| 18226 |
4/8✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 28 times.
|
28 | write_bin_log(thd, true, thd->query().str, thd->query().length)) { |
| 18227 | /* | ||
| 18228 | We can't revert replacement of old table version with a new one | ||
| 18229 | at this point. So, if possible, commit the statement to avoid | ||
| 18230 | new table version being emptied by statement rollback. | ||
| 18231 | */ | ||
| 18232 | ✗ | if (!thd->transaction_rollback_request) { | |
| 18233 | ✗ | (void)trans_commit_stmt(thd); | |
| 18234 | ✗ | (void)trans_commit_implicit(thd); | |
| 18235 | } | ||
| 18236 | ✗ | return true; | |
| 18237 | } | ||
| 18238 | |||
| 18239 | // Do implicit commit for consistency with non-temporary table case/ | ||
| 18240 |
5/10✓ Branch 0 taken 1141 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1141 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1141 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1141 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 1141 times.
|
1141 | if (trans_commit_stmt(thd) || trans_commit_implicit(thd)) return true; |
| 18241 | |||
| 18242 | 1141 | goto end_temporary; | |
| 18243 | } | ||
| 18244 | |||
| 18245 | /* | ||
| 18246 | Close the intermediate table that will be the new table, but do | ||
| 18247 | not delete it! Even though MERGE tables do not have their children | ||
| 18248 | attached here it is safe to call close_temporary_table(). | ||
| 18249 | */ | ||
| 18250 |
1/2✓ Branch 0 taken 18376 times.
✗ Branch 1 not taken.
|
18376 | close_temporary_table(thd, new_table, true, false); |
| 18251 | 18376 | new_table = nullptr; | |
| 18252 | |||
| 18253 |
3/4✓ Branch 0 taken 18183 times.
✓ Branch 1 taken 193 times.
✓ Branch 2 taken 18183 times.
✗ Branch 3 not taken.
|
18376 | DEBUG_SYNC(thd, "alter_table_before_rename_result_table"); |
| 18254 |
4/6✓ Branch 0 taken 18376 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 18375 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
|
18376 | DBUG_EXECUTE_IF("exit_after_alter_table_before_rename", { |
| 18255 | my_error(ER_UNKNOWN_ERROR, MYF(0)); | ||
| 18256 | return true; | ||
| 18257 | }); | ||
| 18258 | |||
| 18259 | /* | ||
| 18260 | Data is copied. Now we: | ||
| 18261 | 1) Wait until all other threads will stop using old version of table | ||
| 18262 | by upgrading shared metadata lock to exclusive one. | ||
| 18263 | 2) Close instances of table open by this thread and replace them | ||
| 18264 | with placeholders to simplify reopen process. | ||
| 18265 | 3) Rename the old table to a temp name, rename the new one to the | ||
| 18266 | old name. | ||
| 18267 | 4) If we are under LOCK TABLES and don't do ALTER TABLE ... RENAME | ||
| 18268 | we reopen new version of table. | ||
| 18269 | 5) Write statement to the binary log. | ||
| 18270 | 6) If we are under LOCK TABLES and do ALTER TABLE ... RENAME we | ||
| 18271 | remove placeholders and release metadata locks. | ||
| 18272 | 7) If we are not not under LOCK TABLES we rely on the caller | ||
| 18273 | (mysql_execute_command()) to release metadata locks. | ||
| 18274 | */ | ||
| 18275 | |||
| 18276 |
1/2✓ Branch 0 taken 18375 times.
✗ Branch 1 not taken.
|
18375 | THD_STAGE_INFO(thd, stage_rename_result_table); |
| 18277 | |||
| 18278 |
3/4✓ Branch 0 taken 18375 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 18373 times.
|
18375 | if (wait_while_table_is_used(thd, table, HA_EXTRA_PREPARE_FOR_RENAME)) |
| 18279 | 2 | goto err_new_table_cleanup; | |
| 18280 | |||
| 18281 |
2/4✓ Branch 0 taken 18373 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 18373 times.
|
18373 | if (collect_and_lock_fk_tables_for_complex_alter_table( |
| 18282 | thd, table_list, old_table_def, &alter_ctx, alter_info, old_db_type, | ||
| 18283 | new_db_type, &fk_invalidator)) | ||
| 18284 | ✗ | goto err_new_table_cleanup; | |
| 18285 | |||
| 18286 | /* | ||
| 18287 | To ensure DDL atomicity after this point support from both old and | ||
| 18288 | new engines is necessary. If either of them lacks such support let | ||
| 18289 | us commit transaction so changes to data-dictionary are more closely | ||
| 18290 | reflect situations in SEs. | ||
| 18291 | |||
| 18292 | Also if new SE supports atomic DDL then we have not stored new table | ||
| 18293 | definition in on-disk data-dictionary so far. It is time to do this | ||
| 18294 | now if ALTER TABLE as a whole won't be atomic. | ||
| 18295 | */ | ||
| 18296 |
2/2✓ Branch 0 taken 12143 times.
✓ Branch 1 taken 6230 times.
|
18373 | if (!atomic_replace) { |
| 18297 |
3/4✓ Branch 0 taken 684 times.
✓ Branch 1 taken 11459 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12143 times.
|
12827 | if ((new_db_type->flags & HTON_SUPPORTS_ATOMIC_DDL) && |
| 18298 |
2/4✓ Branch 0 taken 684 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 684 times.
|
684 | thd->dd_client()->store(non_dd_table_def.get())) |
| 18299 | ✗ | goto err_new_table_cleanup; | |
| 18300 | |||
| 18301 | /* Prevent intermediate commits to invoke commit order */ | ||
| 18302 |
1/2✓ Branch 0 taken 12143 times.
✗ Branch 1 not taken.
|
12143 | Implicit_substatement_state_guard substatement_guard(thd); |
| 18303 | |||
| 18304 |
5/10✓ Branch 0 taken 12143 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12143 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12143 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 12143 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 12143 times.
|
12143 | if (trans_commit_stmt(thd) || trans_commit_implicit(thd)) |
| 18305 | ✗ | goto err_new_table_cleanup; | |
| 18306 | |||
| 18307 | // Safety, in-memory dd::Table is no longer totally correct. | ||
| 18308 | 12143 | non_dd_table_def.reset(); | |
| 18309 |
1/2✓ Branch 0 taken 12143 times.
✗ Branch 1 not taken.
|
12143 | } |
| 18310 | |||
| 18311 | char backup_name[32]; | ||
| 18312 | assert(sizeof(my_thread_id) == 4); | ||
| 18313 | 18373 | snprintf(backup_name, sizeof(backup_name), "%s2-%lx-%x", tmp_file_prefix, | |
| 18314 | current_pid, thd->thread_id()); | ||
| 18315 |
3/4✓ Branch 0 taken 687 times.
✓ Branch 1 taken 17686 times.
✓ Branch 2 taken 687 times.
✗ Branch 3 not taken.
|
18373 | if (lower_case_table_names) my_casedn_str(files_charset_info, backup_name); |
| 18316 | |||
| 18317 |
1/2✓ Branch 0 taken 18373 times.
✗ Branch 1 not taken.
|
18373 | close_all_tables_for_name(thd, table->s, false, nullptr); |
| 18318 | 18373 | table_list->table = table = nullptr; /* Safety */ | |
| 18319 | |||
| 18320 | /* | ||
| 18321 | Rename the old version to temporary name to have a backup in case | ||
| 18322 | anything goes wrong while renaming the new table. | ||
| 18323 | |||
| 18324 | Take the X metadata lock on this temporary name too. This ensures that | ||
| 18325 | concurrent I_S queries won't try to open it. Assert to ensure we do not | ||
| 18326 | come here when ALTERing temporary table. | ||
| 18327 | */ | ||
| 18328 | { | ||
| 18329 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18373 times.
|
18373 | assert(!is_tmp_table); |
| 18330 | 18373 | MDL_request backup_name_mdl_request; | |
| 18331 |
1/2✓ Branch 0 taken 18373 times.
✗ Branch 1 not taken.
|
18373 | MDL_REQUEST_INIT(&backup_name_mdl_request, MDL_key::TABLE, alter_ctx.db, |
| 18332 | backup_name, MDL_EXCLUSIVE, MDL_STATEMENT); | ||
| 18333 |
1/2✓ Branch 0 taken 18373 times.
✗ Branch 1 not taken.
|
18373 | dd::cache::Dictionary_client::Auto_releaser releaser_2(thd->dd_client()); |
| 18334 | 18373 | const dd::Table *backup_table = nullptr; | |
| 18335 | |||
| 18336 | 55119 | if (thd->mdl_context.acquire_lock(&backup_name_mdl_request, | |
| 18337 |
2/4✓ Branch 0 taken 18373 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18373 times.
✗ Branch 3 not taken.
|
36746 | thd->variables.lock_wait_timeout) || |
| 18338 |
7/18✓ Branch 0 taken 18373 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18373 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18373 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 18373 times.
✓ Branch 8 taken 18373 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 18373 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 18373 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
|
36746 | thd->dd_client()->acquire(alter_ctx.db, backup_name, &backup_table)) { |
| 18339 | /* purecov: begin tested */ | ||
| 18340 | /* | ||
| 18341 | We need to clear THD::transaction_rollback_request (which might | ||
| 18342 | be set due to MDL deadlock) before attempting to remove new version | ||
| 18343 | of table. | ||
| 18344 | */ | ||
| 18345 | ✗ | if (thd->transaction_rollback_request) { | |
| 18346 | ✗ | trans_rollback_stmt(thd); | |
| 18347 | ✗ | trans_rollback(thd); | |
| 18348 | } | ||
| 18349 | |||
| 18350 | ✗ | if (!atomic_replace) { | |
| 18351 | ✗ | (void)quick_rm_table(thd, new_db_type, alter_ctx.new_db, | |
| 18352 | alter_ctx.tmp_name, FN_IS_TMP); | ||
| 18353 | } | ||
| 18354 | ✗ | goto err_with_mdl; | |
| 18355 | /* purecov: end */ | ||
| 18356 | } | ||
| 18357 | |||
| 18358 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18373 times.
|
18373 | if (backup_table != nullptr) { |
| 18359 | /* purecov: begin tested */ | ||
| 18360 | ✗ | my_error(ER_TABLE_EXISTS_ERROR, MYF(0), backup_name); | |
| 18361 | |||
| 18362 | ✗ | if (!atomic_replace) { | |
| 18363 | ✗ | (void)quick_rm_table(thd, new_db_type, alter_ctx.new_db, | |
| 18364 | alter_ctx.tmp_name, FN_IS_TMP); | ||
| 18365 | } | ||
| 18366 | ✗ | goto err_with_mdl; | |
| 18367 | /* purecov: end */ | ||
| 18368 | } | ||
| 18369 |
1/2✓ Branch 0 taken 18373 times.
✗ Branch 1 not taken.
|
18373 | } |
| 18370 | |||
| 18371 |
5/6✓ Branch 0 taken 6230 times.
✓ Branch 1 taken 12143 times.
✓ Branch 2 taken 18358 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 18353 times.
|
18373 | if (mysql_rename_table(thd, old_db_type, alter_ctx.db, alter_ctx.table_name, |
| 18372 | alter_ctx.db, alter_ctx.table_name, *schema, | ||
| 18373 | alter_ctx.db, backup_name, | ||
| 18374 | FN_TO_IS_TMP | (atomic_replace ? NO_DD_COMMIT : 0) | | ||
| 18375 | NO_FK_RENAME | NO_CC_RENAME)) { | ||
| 18376 | // Rename to temporary name failed, delete the new table, abort ALTER. | ||
| 18377 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | if (!atomic_replace) { |
| 18378 | /* | ||
| 18379 | In non-atomic mode situations when the SE has requested rollback | ||
| 18380 | should be handled already, by executing rollback right inside | ||
| 18381 | mysql_rename_table() call. | ||
| 18382 | */ | ||
| 18383 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 | assert(!thd->transaction_rollback_request); |
| 18384 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | (void)quick_rm_table(thd, new_db_type, alter_ctx.new_db, |
| 18385 | alter_ctx.tmp_name, FN_IS_TMP); | ||
| 18386 | } | ||
| 18387 | 5 | goto err_with_mdl; | |
| 18388 | } | ||
| 18389 | |||
| 18390 | /* | ||
| 18391 | The below code assumes that only SE capable of atomic DDL support FK. | ||
| 18392 | This is somewhat simplifies error handling below. | ||
| 18393 | |||
| 18394 | Note that we need to handle FKs atomically with this rename in order | ||
| 18395 | to handle scenario when, for example, MyISAM table is altered to InnoDB | ||
| 18396 | SE and some FKs are added at the same time. | ||
| 18397 | */ | ||
| 18398 |
3/4✓ Branch 0 taken 6899 times.
✓ Branch 1 taken 11454 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6899 times.
|
18353 | assert(!(new_db_type->flags & HTON_SUPPORTS_FOREIGN_KEYS) || |
| 18399 | (new_db_type->flags & HTON_SUPPORTS_ATOMIC_DDL)); | ||
| 18400 | |||
| 18401 | /* | ||
| 18402 | We also assume that we can't have non-atomic ALTER TABLE which | ||
| 18403 | will preserve any foreign keys (i.e. such ALTER TABLE can only | ||
| 18404 | drop all foreign keys on the table, or add new foreign keys to | ||
| 18405 | table which previously didn't have any). | ||
| 18406 | */ | ||
| 18407 |
3/4✓ Branch 0 taken 12138 times.
✓ Branch 1 taken 6215 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12138 times.
|
18353 | assert(atomic_replace || alter_ctx.fk_count == 0); |
| 18408 | |||
| 18409 | /* | ||
| 18410 | If both old and new SEs support atomic DDL then we have not stored | ||
| 18411 | new table definition in on-disk data-dictionary so far. It is time | ||
| 18412 | to do this now. However, before doing this we need to rename foreign | ||
| 18413 | keys in old table definition to temporary names to avoid conflicts | ||
| 18414 | with duplicate names. | ||
| 18415 | */ | ||
| 18416 |
2/2✓ Branch 0 taken 6215 times.
✓ Branch 1 taken 12138 times.
|
18353 | if (atomic_replace) { |
| 18417 |
3/4✓ Branch 0 taken 48 times.
✓ Branch 1 taken 6167 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6215 times.
|
6263 | if (alter_ctx.fk_count > 0 && |
| 18418 |
2/4✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 48 times.
|
48 | adjust_foreign_key_names_for_old_table_version(thd, alter_ctx.db, |
| 18419 | backup_name)) | ||
| 18420 | ✗ | goto err_with_mdl; | |
| 18421 | |||
| 18422 |
2/4✓ Branch 0 taken 6215 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6215 times.
|
6215 | if (thd->dd_client()->store(non_dd_table_def.get())) goto err_with_mdl; |
| 18423 | |||
| 18424 | 6215 | const dd::Table *stored_table = nullptr; | |
| 18425 | |||
| 18426 |
4/8✓ Branch 0 taken 6215 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6215 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6215 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 6215 times.
|
6215 | if (thd->dd_client()->acquire(alter_ctx.new_db, alter_ctx.tmp_name, |
| 18427 | &stored_table)) { | ||
| 18428 | ✗ | DBUG_LOG("zip_dict", | |
| 18429 | "Acquiring dictionary table object failed " | ||
| 18430 | " for query " | ||
| 18431 | << thd->query().str << " table_db: " << alter_ctx.new_db | ||
| 18432 | << " table_name: " << alter_ctx.tmp_name); | ||
| 18433 | |||
| 18434 | ✗ | goto err_with_mdl; | |
| 18435 | } | ||
| 18436 | |||
| 18437 |
2/4✓ Branch 0 taken 6215 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6215 times.
|
6215 | if (compression_dict::cols_table_insert(thd, *stored_table)) |
| 18438 | ✗ | goto err_with_mdl; | |
| 18439 | |||
| 18440 | // Safety, in-memory dd::Table is no longer totally correct. | ||
| 18441 | 6215 | non_dd_table_def.reset(); | |
| 18442 | } | ||
| 18443 | |||
| 18444 | // Rename the new table to the correct name. | ||
| 18445 | 55031 | if (mysql_rename_table( | |
| 18446 | thd, new_db_type, alter_ctx.new_db, alter_ctx.tmp_name, alter_ctx.db, | ||
| 18447 | alter_ctx.table_name, *new_schema, alter_ctx.new_db, | ||
| 18448 | alter_ctx.new_alias, | ||
| 18449 | (FN_FROM_IS_TMP | | ||
| 18450 | 18353 | ((new_db_type->flags & HTON_SUPPORTS_ATOMIC_DDL) ? NO_DD_COMMIT | |
| 18451 |
1/2✓ Branch 0 taken 18339 times.
✗ Branch 1 not taken.
|
18353 | : 0) | |
| 18452 |
2/2✓ Branch 0 taken 112 times.
✓ Branch 1 taken 18241 times.
|
18353 | (alter_ctx.is_table_renamed() ? 0 : NO_FK_RENAME | NO_CC_RENAME))) || |
| 18453 |
2/2✓ Branch 0 taken 6880 times.
✓ Branch 1 taken 11454 times.
|
18334 | ((new_db_type->flags & HTON_SUPPORTS_FOREIGN_KEYS) && |
| 18454 |
2/4✓ Branch 0 taken 6880 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6880 times.
✗ Branch 3 not taken.
|
6880 | adjust_fks_for_complex_alter_table(thd, table_list, &alter_ctx, |
| 18455 | alter_info, new_db_type, | ||
| 18456 |
4/4✓ Branch 0 taken 18334 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 18334 times.
|
36673 | &fk_invalidator)) || |
| 18457 | /* | ||
| 18458 | Try commit changes if ALTER TABLE as whole is not atomic and we have | ||
| 18459 | not done this in the above mysql_rename_table() call. | ||
| 18460 | */ | ||
| 18461 |
4/4✓ Branch 0 taken 12136 times.
✓ Branch 1 taken 6198 times.
✓ Branch 2 taken 682 times.
✓ Branch 3 taken 11454 times.
|
18334 | (!atomic_replace && (new_db_type->flags & HTON_SUPPORTS_ATOMIC_DDL) && |
| 18462 |
2/4✓ Branch 0 taken 682 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 682 times.
|
682 | trans_intermediate_ddl_commit(thd, false))) { |
| 18463 | // Rename failed, delete the temporary table. | ||
| 18464 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
|
5 | if (!atomic_replace) { |
| 18465 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (new_db_type->flags & HTON_SUPPORTS_ATOMIC_DDL) { |
| 18466 | /* | ||
| 18467 | If ALTER TABLE as whole is not atomic and the above rename or | ||
| 18468 | FK changes have failed without cleaning up after themselves, | ||
| 18469 | we need to do this now. | ||
| 18470 | */ | ||
| 18471 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | (void)trans_intermediate_ddl_commit(thd, true); |
| 18472 | } | ||
| 18473 | |||
| 18474 | /* | ||
| 18475 | In non-atomic mode situations when the SE has requested rollback | ||
| 18476 | should be handled already. | ||
| 18477 | */ | ||
| 18478 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | assert(!thd->transaction_rollback_request); |
| 18479 | |||
| 18480 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | (void)quick_rm_table(thd, new_db_type, alter_ctx.new_db, |
| 18481 | alter_ctx.tmp_name, FN_IS_TMP); | ||
| 18482 | |||
| 18483 | // Restore the backup of the original table to its original name. | ||
| 18484 | // If the operation fails, we need to retry it to avoid leaving | ||
| 18485 | // the dictionary inconsistent. | ||
| 18486 | // | ||
| 18487 | // This hack might become unnecessary once InnoDB stops acquiring | ||
| 18488 | // gap locks on DD tables (which might cause deadlocks). | ||
| 18489 | 2 | uint retries = 20; | |
| 18490 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
4 | while (retries-- && |
| 18491 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
2 | mysql_rename_table( |
| 18492 | thd, old_db_type, alter_ctx.db, backup_name, alter_ctx.db, | ||
| 18493 | backup_name, *schema, alter_ctx.db, alter_ctx.alias, | ||
| 18494 | FN_FROM_IS_TMP | NO_FK_CHECKS | NO_FK_RENAME | NO_CC_RENAME)) | ||
| 18495 | ; | ||
| 18496 | } | ||
| 18497 | 5 | goto err_with_mdl; | |
| 18498 | } | ||
| 18499 | |||
| 18500 | /* | ||
| 18501 | If ALTER TABLE is non-atomic and fails after this point it can add | ||
| 18502 | foreign keys and such addition won't be reverted. So we need to | ||
| 18503 | invalidate table objects for foreign key parents even on error. | ||
| 18504 | */ | ||
| 18505 |
2/2✓ Branch 0 taken 12136 times.
✓ Branch 1 taken 6198 times.
|
18334 | if (!atomic_replace) invalidate_fk_parents_on_error = true; |
| 18506 | |||
| 18507 | // Handle trigger name, check constraint names and histograms statistics. | ||
| 18508 | { | ||
| 18509 | 18334 | dd::Table *backup_table = nullptr; | |
| 18510 | 18334 | dd::Table *new_dd_table = nullptr; | |
| 18511 |
3/10✓ Branch 0 taken 18334 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18334 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 18334 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
36668 | if (thd->dd_client()->acquire_for_modification(alter_ctx.db, backup_name, |
| 18512 |
3/6✓ Branch 0 taken 18334 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18334 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18334 times.
✗ Branch 5 not taken.
|
55002 | &backup_table) || |
| 18513 |
7/18✓ Branch 0 taken 18334 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18334 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18334 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 18334 times.
✓ Branch 8 taken 18334 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 18334 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 18334 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
|
36668 | thd->dd_client()->acquire_for_modification( |
| 18514 | alter_ctx.new_db, alter_ctx.new_alias, &new_dd_table)) | ||
| 18515 | ✗ | goto err_with_mdl; | |
| 18516 |
2/4✓ Branch 0 taken 18334 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18334 times.
✗ Branch 3 not taken.
|
18334 | assert(backup_table != nullptr && new_dd_table != nullptr); |
| 18517 | |||
| 18518 | /* | ||
| 18519 | Check if this is an ALTER command that will cause histogram statistics to | ||
| 18520 | become invalid. If that is the case; remove the histogram statistics. | ||
| 18521 | |||
| 18522 | This will take care of scenarios when COPY alter is used, but not INPLACE. | ||
| 18523 | Do this before the commit for non-transactional tables, because the | ||
| 18524 | new_dd_table is invalidated on commit. | ||
| 18525 | */ | ||
| 18526 |
2/4✓ Branch 0 taken 18334 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 18334 times.
|
18334 | if (alter_table_drop_histograms(thd, table_list, alter_info, create_info, |
| 18527 | columns, backup_table, new_dd_table)) | ||
| 18528 | ✗ | goto err_with_mdl; /* purecov: deadcode */ | |
| 18529 | |||
| 18530 |
1/2✓ Branch 0 taken 18334 times.
✗ Branch 1 not taken.
|
18334 | bool update = (new_dd_table->check_constraints()->size() > 0); |
| 18531 | // Set mode for new_dd_table's check constraints. | ||
| 18532 |
1/2✓ Branch 0 taken 18334 times.
✗ Branch 1 not taken.
|
18334 | set_check_constraints_alter_mode(new_dd_table, alter_info); |
| 18533 | |||
| 18534 | /* | ||
| 18535 | Check constraint names are unique per schema, we cannot create them while | ||
| 18536 | both table version exists. Adjust check constraint names in old table | ||
| 18537 | version. | ||
| 18538 | */ | ||
| 18539 |
2/4✓ Branch 0 taken 18334 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 18334 times.
|
18334 | if (adjust_check_constraint_names_for_old_table_version(thd, alter_ctx.db, |
| 18540 | backup_table)) | ||
| 18541 | ✗ | goto err_with_mdl; | |
| 18542 | |||
| 18543 | // Reset check constraint's mode. | ||
| 18544 |
1/2✓ Branch 0 taken 18334 times.
✗ Branch 1 not taken.
|
18334 | reset_check_constraints_alter_mode(new_dd_table); |
| 18545 | |||
| 18546 | /* | ||
| 18547 | Since trigger names have to be unique per schema, we cannot | ||
| 18548 | create them while both the old and the tmp version of the | ||
| 18549 | table exist. | ||
| 18550 | */ | ||
| 18551 |
3/4✓ Branch 0 taken 18334 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 18306 times.
|
18334 | if (backup_table->has_trigger()) { |
| 18552 |
1/2✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
|
28 | new_dd_table->copy_triggers(backup_table); |
| 18553 |
1/2✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
|
28 | backup_table->drop_all_triggers(); |
| 18554 | 28 | update = true; | |
| 18555 | } | ||
| 18556 |
5/6✓ Branch 0 taken 18334 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18236 times.
✓ Branch 3 taken 98 times.
✓ Branch 4 taken 13 times.
✓ Branch 5 taken 18321 times.
|
36570 | if (!is_checked_for_upgrade(*new_dd_table) && |
| 18557 |
3/4✓ Branch 0 taken 18236 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 18223 times.
|
18236 | is_checked_for_upgrade(*backup_table)) { |
| 18558 |
1/2✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
|
13 | new_dd_table->mark_as_checked_for_upgrade(); |
| 18559 | 13 | update = true; | |
| 18560 | } | ||
| 18561 |
2/2✓ Branch 0 taken 493 times.
✓ Branch 1 taken 17841 times.
|
18334 | if (update) { |
| 18562 |
3/6✓ Branch 0 taken 493 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 493 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 493 times.
|
986 | if (thd->dd_client()->update(backup_table) || |
| 18563 |
2/4✓ Branch 0 taken 493 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 493 times.
|
493 | thd->dd_client()->update(new_dd_table)) |
| 18564 | ✗ | goto err_with_mdl; | |
| 18565 | |||
| 18566 | /* Prevent intermediate commits to invoke commit order */ | ||
| 18567 |
1/2✓ Branch 0 taken 493 times.
✗ Branch 1 not taken.
|
493 | Implicit_substatement_state_guard substatement_guard(thd); |
| 18568 |
7/12✓ Branch 0 taken 37 times.
✓ Branch 1 taken 456 times.
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 37 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 37 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 37 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 493 times.
|
493 | if (!atomic_replace && (trans_commit_stmt(thd) || trans_commit(thd))) |
| 18569 | ✗ | goto err_with_mdl; | |
| 18570 |
1/2✓ Branch 0 taken 493 times.
✗ Branch 1 not taken.
|
493 | } |
| 18571 | } | ||
| 18572 | |||
| 18573 | // If the ALTER command was a rename, rename any existing histograms. | ||
| 18574 |
3/4✓ Branch 0 taken 112 times.
✓ Branch 1 taken 18222 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18334 times.
|
18446 | if (alter_ctx.is_table_renamed() && |
| 18575 |
2/4✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 112 times.
|
112 | rename_histograms(thd, table_list->db, table_list->table_name, new_db, |
| 18576 | new_name)) { | ||
| 18577 | ✗ | goto err_with_mdl; /* purecov: deadcode */ | |
| 18578 | } | ||
| 18579 | |||
| 18580 | // ALTER TABLE succeeded, delete the backup of the old table. | ||
| 18581 |
4/6✓ Branch 0 taken 6198 times.
✓ Branch 1 taken 12136 times.
✓ Branch 2 taken 18320 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 18320 times.
|
18334 | if (quick_rm_table(thd, old_db_type, alter_ctx.db, backup_name, |
| 18582 | FN_IS_TMP | (atomic_replace ? NO_DD_COMMIT : 0))) { | ||
| 18583 | /* | ||
| 18584 | The fact that deletion of the backup failed is not critical | ||
| 18585 | error, but still worth reporting as it might indicate serious | ||
| 18586 | problem with server. | ||
| 18587 | |||
| 18588 | TODO: In !atomic_replace case we might need to do FK parents | ||
| 18589 | invalidation here. However currently our FKs are not | ||
| 18590 | even named correctly at this point, so we postpone | ||
| 18591 | fixing this issue until we solve FK naming problem. | ||
| 18592 | */ | ||
| 18593 | ✗ | goto err_with_mdl; | |
| 18594 | } | ||
| 18595 | |||
| 18596 | 18320 | end_inplace_noop: | |
| 18597 | |||
| 18598 |
1/2✓ Branch 0 taken 18554 times.
✗ Branch 1 not taken.
|
18554 | THD_STAGE_INFO(thd, stage_end); |
| 18599 | |||
| 18600 |
2/6✓ Branch 0 taken 18554 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 18554 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
18554 | DBUG_EXECUTE_IF("sleep_alter_before_main_binlog", my_sleep(6000000);); |
| 18601 |
3/4✓ Branch 0 taken 18357 times.
✓ Branch 1 taken 197 times.
✓ Branch 2 taken 18357 times.
✗ Branch 3 not taken.
|
18554 | DEBUG_SYNC(thd, "alter_table_before_main_binlog"); |
| 18602 | |||
| 18603 | 37108 | ha_binlog_log_query(thd, create_info->db_type, LOGCOM_ALTER_TABLE, | |
| 18604 |
3/6✓ Branch 0 taken 18554 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18554 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18554 times.
✗ Branch 5 not taken.
|
18554 | thd->query().str, thd->query().length, alter_ctx.db, |
| 18605 | alter_ctx.table_name); | ||
| 18606 | |||
| 18607 |
5/6✓ Branch 0 taken 14591 times.
✓ Branch 1 taken 3963 times.
✓ Branch 2 taken 14173 times.
✓ Branch 3 taken 418 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 14173 times.
|
18554 | assert(!(mysql_bin_log.is_open() && |
| 18608 | thd->is_current_stmt_binlog_format_row() && | ||
| 18609 | (create_info->options & HA_LEX_CREATE_TMP_TABLE))); | ||
| 18610 | |||
| 18611 | /* | ||
| 18612 | If this is no-op ALTER TABLE we don't have transaction started. | ||
| 18613 | We can't use binlog's trx cache in this case as it requires active | ||
| 18614 | transaction with valid XID. | ||
| 18615 | */ | ||
| 18616 |
5/8✓ Branch 0 taken 18554 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18554 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18554 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✓ Branch 7 taken 18550 times.
|
18554 | if (write_bin_log(thd, true, thd->query().str, thd->query().length, |
| 18617 |
4/4✓ Branch 0 taken 6332 times.
✓ Branch 1 taken 12222 times.
✓ Branch 2 taken 6184 times.
✓ Branch 3 taken 148 times.
|
18554 | atomic_replace && !is_noop)) |
| 18618 | 4 | goto err_with_mdl; | |
| 18619 | |||
| 18620 |
2/2✓ Branch 0 taken 18316 times.
✓ Branch 1 taken 234 times.
|
18550 | if (!is_noop) { |
| 18621 |
1/2✓ Branch 0 taken 18316 times.
✗ Branch 1 not taken.
|
18316 | Uncommitted_tables_guard uncommitted_tables(thd); |
| 18622 | |||
| 18623 |
1/2✓ Branch 0 taken 18316 times.
✗ Branch 1 not taken.
|
18316 | uncommitted_tables.add_table(table_list); |
| 18624 | |||
| 18625 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18316 times.
|
18316 | if (update_referencing_views_metadata(thd, table_list, new_db, new_name, |
| 18626 |
1/2✓ Branch 0 taken 18316 times.
✗ Branch 1 not taken.
|
18316 | !atomic_replace, &uncommitted_tables)) |
| 18627 | ✗ | goto err_with_mdl; | |
| 18628 | |||
| 18629 |
2/2✓ Branch 0 taken 108 times.
✓ Branch 1 taken 18208 times.
|
18316 | if (alter_ctx.is_table_renamed()) |
| 18630 |
1/2✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
|
108 | tdc_remove_table(thd, TDC_RT_REMOVE_ALL, alter_ctx.new_db, |
| 18631 | alter_ctx.new_name, false); | ||
| 18632 |
1/2✓ Branch 0 taken 18316 times.
✗ Branch 1 not taken.
|
18316 | } |
| 18633 | |||
| 18634 | // Commit if it was not done before in order to be able to reopen tables. | ||
| 18635 |
7/12✓ Branch 0 taken 6331 times.
✓ Branch 1 taken 12219 times.
✓ Branch 2 taken 6331 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6331 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6328 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 6328 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 18547 times.
|
18550 | if (atomic_replace && (trans_commit_stmt(thd) || trans_commit_implicit(thd))) |
| 18636 | ✗ | goto err_with_mdl; | |
| 18637 | |||
| 18638 |
3/4✓ Branch 0 taken 7009 times.
✓ Branch 1 taken 11538 times.
✓ Branch 2 taken 7009 times.
✗ Branch 3 not taken.
|
18547 | if ((new_db_type->flags & HTON_SUPPORTS_ATOMIC_DDL) && new_db_type->post_ddl) |
| 18639 |
1/2✓ Branch 0 taken 7001 times.
✗ Branch 1 not taken.
|
7009 | new_db_type->post_ddl(thd); |
| 18640 |
3/4✓ Branch 0 taken 6393 times.
✓ Branch 1 taken 12146 times.
✓ Branch 2 taken 6393 times.
✗ Branch 3 not taken.
|
18539 | if ((old_db_type->flags & HTON_SUPPORTS_ATOMIC_DDL) && old_db_type->post_ddl) |
| 18641 |
1/2✓ Branch 0 taken 6393 times.
✗ Branch 1 not taken.
|
6393 | old_db_type->post_ddl(thd); |
| 18642 | |||
| 18643 | #ifndef WORKAROUND_TO_BE_REMOVED_BY_WL6049 | ||
| 18644 | { | ||
| 18645 | TABLE_LIST table_list_reopen(alter_ctx.new_db, alter_ctx.new_name, | ||
| 18646 |
1/2✓ Branch 0 taken 18539 times.
✗ Branch 1 not taken.
|
18539 | alter_ctx.new_alias, TL_READ); |
| 18647 | 18539 | table_list_reopen.mdl_request.ticket = | |
| 18648 |
2/2✓ Branch 0 taken 108 times.
✓ Branch 1 taken 18431 times.
|
18539 | alter_ctx.is_table_renamed() ? alter_ctx.target_mdl_request.ticket |
| 18649 | : mdl_ticket; | ||
| 18650 | |||
| 18651 |
1/2✓ Branch 0 taken 18539 times.
✗ Branch 1 not taken.
|
18539 | Open_table_context ot_ctx(thd, MYSQL_OPEN_REOPEN); |
| 18652 | |||
| 18653 |
2/4✓ Branch 0 taken 18539 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 18539 times.
|
18539 | if (open_table(thd, &table_list_reopen, &ot_ctx)) return true; |
| 18654 | |||
| 18655 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18539 times.
|
18539 | assert(table_list_reopen.table == thd->open_tables); |
| 18656 |
1/2✓ Branch 0 taken 18539 times.
✗ Branch 1 not taken.
|
18539 | close_thread_table(thd, &thd->open_tables); |
| 18657 | } | ||
| 18658 | #endif | ||
| 18659 | |||
| 18660 | 75251 | end_inplace: | |
| 18661 | |||
| 18662 |
1/2✓ Branch 0 taken 75251 times.
✗ Branch 1 not taken.
|
75251 | fk_invalidator.invalidate(thd); |
| 18663 | |||
| 18664 |
2/2✓ Branch 0 taken 266 times.
✓ Branch 1 taken 74985 times.
|
75251 | if (alter_ctx.is_table_renamed()) |
| 18665 |
1/2✓ Branch 0 taken 266 times.
✗ Branch 1 not taken.
|
266 | thd->locked_tables_list.rename_locked_table( |
| 18666 | table_list, alter_ctx.new_db, alter_ctx.new_name, | ||
| 18667 | alter_ctx.target_mdl_request.ticket); | ||
| 18668 | |||
| 18669 | { | ||
| 18670 |
1/2✓ Branch 0 taken 75251 times.
✗ Branch 1 not taken.
|
75251 | bool reopen_error = thd->locked_tables_list.reopen_tables(thd); |
| 18671 | |||
| 18672 |
2/2✓ Branch 0 taken 75168 times.
✓ Branch 1 taken 83 times.
|
75251 | if (thd->locked_tables_mode == LTM_LOCK_TABLES || |
| 18673 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 75168 times.
|
75168 | thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES) { |
| 18674 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 71 times.
|
83 | if (alter_ctx.is_table_renamed()) { |
| 18675 | /* | ||
| 18676 | Release metadata lock on old table name and keep the lock | ||
| 18677 | on the new one. We have to ignore reopen_error in this case | ||
| 18678 | as we will mess up FK invariants for LOCK TABLES otherwise. | ||
| 18679 | */ | ||
| 18680 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | thd->mdl_context.release_all_locks_for_name(mdl_ticket); |
| 18681 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | thd->mdl_context.set_lock_duration(alter_ctx.target_mdl_request.ticket, |
| 18682 | MDL_EXPLICIT); | ||
| 18683 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | alter_ctx.target_mdl_request.ticket->downgrade_lock( |
| 18684 | MDL_SHARED_NO_READ_WRITE); | ||
| 18685 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 10 times.
|
12 | if (alter_ctx.is_database_changed()) |
| 18686 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | thd->mdl_context.set_lock_duration( |
| 18687 | alter_ctx.target_db_mdl_request.ticket, MDL_EXPLICIT); | ||
| 18688 | } else | ||
| 18689 |
1/2✓ Branch 0 taken 71 times.
✗ Branch 1 not taken.
|
71 | mdl_ticket->downgrade_lock(MDL_SHARED_NO_READ_WRITE); |
| 18690 | } | ||
| 18691 | |||
| 18692 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 75251 times.
|
75251 | if (reopen_error) return true; |
| 18693 | } | ||
| 18694 | |||
| 18695 | 75251 | end_temporary: | |
| 18696 | 152784 | snprintf(alter_ctx.tmp_name, sizeof(alter_ctx.tmp_name), | |
| 18697 |
1/2✓ Branch 0 taken 76392 times.
✗ Branch 1 not taken.
|
76392 | ER_THD(thd, ER_INSERT_INFO), (long)(copied + deleted), (long)deleted, |
| 18698 | 76392 | (long)thd->get_stmt_da()->current_statement_cond_count()); | |
| 18699 |
1/2✓ Branch 0 taken 76392 times.
✗ Branch 1 not taken.
|
76392 | my_ok(thd, copied + deleted, 0L, alter_ctx.tmp_name); |
| 18700 | 76392 | return false; | |
| 18701 | |||
| 18702 | 1504 | err_new_table_cleanup: | |
| 18703 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1495 times.
|
1504 | if (create_info->options & HA_LEX_CREATE_TMP_TABLE) { |
| 18704 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 8 times.
|
9 | if (new_table) |
| 18705 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | close_temporary_table(thd, new_table, true, true); |
| 18706 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | else if (!no_ha_table) |
| 18707 | ✗ | rm_temporary_table(thd, new_db_type, alter_ctx.get_tmp_path(), | |
| 18708 | ✗ | non_dd_table_def.get()); | |
| 18709 | } else { | ||
| 18710 | /* close_temporary_table() frees the new_table pointer. */ | ||
| 18711 |
3/4✓ Branch 0 taken 974 times.
✓ Branch 1 taken 521 times.
✓ Branch 2 taken 974 times.
✗ Branch 3 not taken.
|
1495 | if (new_table) close_temporary_table(thd, new_table, true, false); |
| 18712 | |||
| 18713 |
2/2✓ Branch 0 taken 995 times.
✓ Branch 1 taken 500 times.
|
1495 | if (!(new_db_type->flags & HTON_SUPPORTS_ATOMIC_DDL)) { |
| 18714 |
2/2✓ Branch 0 taken 115 times.
✓ Branch 1 taken 880 times.
|
995 | if (no_ha_table) // Only remove from DD. |
| 18715 | { | ||
| 18716 | dd::cache::Dictionary_client::Auto_releaser releaser_3( | ||
| 18717 |
1/2✓ Branch 0 taken 115 times.
✗ Branch 1 not taken.
|
115 | thd->dd_client()); |
| 18718 | 115 | const dd::Table *drop_table_def = nullptr; | |
| 18719 |
4/8✓ Branch 0 taken 115 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 115 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 115 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 115 times.
✗ Branch 7 not taken.
|
115 | if (!thd->dd_client()->acquire(alter_ctx.new_db, alter_ctx.tmp_name, |
| 18720 | &drop_table_def)) { | ||
| 18721 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 115 times.
|
115 | assert(drop_table_def != nullptr); |
| 18722 |
1/2✓ Branch 0 taken 115 times.
✗ Branch 1 not taken.
|
115 | bool result = dd::drop_table(thd, alter_ctx.new_db, |
| 18723 | alter_ctx.tmp_name, *drop_table_def); | ||
| 18724 |
1/2✓ Branch 0 taken 115 times.
✗ Branch 1 not taken.
|
115 | (void)trans_intermediate_ddl_commit(thd, result); |
| 18725 | } | ||
| 18726 | 115 | } else // Remove from both DD and SE. | |
| 18727 |
1/2✓ Branch 0 taken 880 times.
✗ Branch 1 not taken.
|
880 | (void)quick_rm_table(thd, new_db_type, alter_ctx.new_db, |
| 18728 | alter_ctx.tmp_name, FN_IS_TMP); | ||
| 18729 | } else { | ||
| 18730 |
1/2✓ Branch 0 taken 500 times.
✗ Branch 1 not taken.
|
500 | trans_rollback_stmt(thd); |
| 18731 | /* | ||
| 18732 | Full rollback in case we have THD::transaction_rollback_request | ||
| 18733 | and to synchronize DD state in cache and on disk (as statement | ||
| 18734 | rollback doesn't clear DD cache of modified uncommitted objects). | ||
| 18735 | */ | ||
| 18736 |
1/2✓ Branch 0 taken 500 times.
✗ Branch 1 not taken.
|
500 | trans_rollback(thd); |
| 18737 | } | ||
| 18738 |
2/2✓ Branch 0 taken 500 times.
✓ Branch 1 taken 995 times.
|
1495 | if ((new_db_type->flags & HTON_SUPPORTS_ATOMIC_DDL) && |
| 18739 |
1/2✓ Branch 0 taken 500 times.
✗ Branch 1 not taken.
|
500 | new_db_type->post_ddl) |
| 18740 |
1/2✓ Branch 0 taken 500 times.
✗ Branch 1 not taken.
|
500 | new_db_type->post_ddl(thd); |
| 18741 | } | ||
| 18742 | |||
| 18743 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1491 times.
|
1504 | if (alter_ctx.error_if_not_empty & |
| 18744 | Alter_table_ctx::GEOMETRY_WITHOUT_DEFAULT) { | ||
| 18745 |
1/2✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
|
13 | my_error(ER_INVALID_USE_OF_NULL, MYF(0)); |
| 18746 | } | ||
| 18747 | |||
| 18748 | /* | ||
| 18749 | No default value was provided for a DATE/DATETIME field, the | ||
| 18750 | current sql_mode doesn't allow the '0000-00-00' value and | ||
| 18751 | the table to be altered isn't empty. | ||
| 18752 | Report error here. Ignore error checkin for push_zero_date_warning() | ||
| 18753 | as we return true right below. | ||
| 18754 | */ | ||
| 18755 | 3008 | if ((alter_ctx.error_if_not_empty & | |
| 18756 | 8 | Alter_table_ctx::DATETIME_WITHOUT_DEFAULT) && | |
| 18757 |
6/8✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1496 times.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 8 times.
✓ Branch 7 taken 1496 times.
|
1512 | (thd->variables.sql_mode & MODE_NO_ZERO_DATE) && |
| 18758 | 8 | thd->get_stmt_da()->current_row_for_condition()) { | |
| 18759 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | (void)push_zero_date_warning(thd, alter_ctx.datetime_field); |
| 18760 | } | ||
| 18761 | 1504 | return true; | |
| 18762 | |||
| 18763 | 14 | err_with_mdl: | |
| 18764 | /* | ||
| 18765 | An error happened while we were holding exclusive name metadata lock | ||
| 18766 | on table being altered. Before releasing locks we need to rollback | ||
| 18767 | changes to the data-dictionary, storage angine and binary log (if | ||
| 18768 | they were not committed earlier) and execute post DDL hooks. | ||
| 18769 | We also try to reopen old version of the table under LOCK TABLES | ||
| 18770 | if possible. | ||
| 18771 | */ | ||
| 18772 | |||
| 18773 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | trans_rollback_stmt(thd); |
| 18774 | /* | ||
| 18775 | Full rollback in case we have THD::transaction_rollback_request | ||
| 18776 | and to synchronize DD state in cache and on disk (as statement | ||
| 18777 | rollback doesn't clear DD cache of modified uncommitted objects). | ||
| 18778 | */ | ||
| 18779 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | trans_rollback(thd); |
| 18780 |
3/4✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
|
14 | if ((new_db_type->flags & HTON_SUPPORTS_ATOMIC_DDL) && new_db_type->post_ddl) |
| 18781 |
1/2✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 | new_db_type->post_ddl(thd); |
| 18782 |
3/4✓ Branch 0 taken 6 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
|
14 | if ((old_db_type->flags & HTON_SUPPORTS_ATOMIC_DDL) && old_db_type->post_ddl) |
| 18783 |
1/2✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
|
6 | old_db_type->post_ddl(thd); |
| 18784 | |||
| 18785 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 4 times.
|
14 | if (atomic_replace) { |
| 18786 | /* | ||
| 18787 | If both old and new storage engines support atomic DDL all changes | ||
| 18788 | were reverted at this point. So we can safely try to reopen table | ||
| 18789 | under old name. | ||
| 18790 | */ | ||
| 18791 | } else { | ||
| 18792 | /* | ||
| 18793 | If ALTER TABLE ... RENAME ... ALGORITHM=COPY is non-atomic we can't | ||
| 18794 | be sure that rename step was reverted, so we simply remove table | ||
| 18795 | from the list of locked tables. | ||
| 18796 | */ | ||
| 18797 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 7 times.
|
10 | if (alter_ctx.is_table_renamed()) |
| 18798 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | thd->locked_tables_list.unlink_all_closed_tables(thd, nullptr, 0); |
| 18799 | } | ||
| 18800 | |||
| 18801 | /* | ||
| 18802 | ALTER TABLE which changes table storage engine from MyISAM to InnoDB | ||
| 18803 | and adds foreign keys at the same time can fail after installing | ||
| 18804 | new table version. In this case we still need to invalidate table | ||
| 18805 | objects for parent tables to avoid creating discrepancy between | ||
| 18806 | data-dictionary and cache contents. | ||
| 18807 | */ | ||
| 18808 |
3/4✓ Branch 0 taken 3 times.
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
14 | if (invalidate_fk_parents_on_error) fk_invalidator.invalidate(thd); |
| 18809 | |||
| 18810 |
1/2✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
|
14 | (void)thd->locked_tables_list.reopen_tables(thd); |
| 18811 | |||
| 18812 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 4 times.
|
14 | if ((thd->locked_tables_mode == LTM_LOCK_TABLES || |
| 18813 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | thd->locked_tables_mode == LTM_PRELOCKED_UNDER_LOCK_TABLES)) { |
| 18814 | /* | ||
| 18815 | Non-atomic ALTER TABLE ... RENAME ... ALGORITHM=COPY can add | ||
| 18816 | foreign keys if at the same time SE is changed from, e.g., | ||
| 18817 | MyISAM to InnoDB. Since releasing metadata locks on old or new | ||
| 18818 | table name can break FK invariants for LOCK TABLES in various | ||
| 18819 | scenarios we keep both of them. | ||
| 18820 | */ | ||
| 18821 |
5/6✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 1 times.
|
4 | if (!atomic_replace && alter_ctx.is_table_renamed()) { |
| 18822 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | thd->mdl_context.set_lock_duration(alter_ctx.target_mdl_request.ticket, |
| 18823 | MDL_EXPLICIT); | ||
| 18824 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | alter_ctx.target_mdl_request.ticket->downgrade_lock( |
| 18825 | MDL_SHARED_NO_READ_WRITE); | ||
| 18826 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
|
3 | if (alter_ctx.is_database_changed()) |
| 18827 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | thd->mdl_context.set_lock_duration( |
| 18828 | alter_ctx.target_db_mdl_request.ticket, MDL_EXPLICIT); | ||
| 18829 | } | ||
| 18830 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | mdl_ticket->downgrade_lock(MDL_SHARED_NO_READ_WRITE); |
| 18831 | } | ||
| 18832 | |||
| 18833 | 14 | return true; | |
| 18834 | 91451 | } | |
| 18835 | /* mysql_alter_table */ | ||
| 18836 | |||
| 18837 | /** | ||
| 18838 | Prepare the transaction for the alter table's copy phase. | ||
| 18839 | */ | ||
| 18840 | |||
| 18841 | 13461 | bool mysql_trans_prepare_alter_copy_data(THD *thd) { | |
| 18842 |
1/2✓ Branch 0 taken 13461 times.
✗ Branch 1 not taken.
|
13461 | DBUG_TRACE; |
| 18843 | /* | ||
| 18844 | Turn off recovery logging since rollback of an alter table is to | ||
| 18845 | delete the new table so there is no need to log the changes to it. | ||
| 18846 | |||
| 18847 | This needs to be done before external_lock. | ||
| 18848 | |||
| 18849 | Also this prevent intermediate commits to invoke commit order. | ||
| 18850 | */ | ||
| 18851 |
1/2✓ Branch 0 taken 13461 times.
✗ Branch 1 not taken.
|
13461 | Implicit_substatement_state_guard substatement_guard(thd); |
| 18852 | |||
| 18853 |
2/4✓ Branch 0 taken 13461 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 13461 times.
|
13461 | if (ha_enable_transaction(thd, false)) return true; |
| 18854 | 13461 | return false; | |
| 18855 | 13461 | } | |
| 18856 | |||
| 18857 | /** | ||
| 18858 | Commit the copy phase of the alter table. | ||
| 18859 | */ | ||
| 18860 | |||
| 18861 | 13455 | bool mysql_trans_commit_alter_copy_data(THD *thd) { | |
| 18862 | 13455 | bool error = false; | |
| 18863 |
1/2✓ Branch 0 taken 13455 times.
✗ Branch 1 not taken.
|
13455 | DBUG_TRACE; |
| 18864 | |||
| 18865 | /* | ||
| 18866 | Ensure that ha_commit_trans() which is implicitly called by | ||
| 18867 | ha_enable_transaction() doesn't update GTID and slave info states. | ||
| 18868 | Also this prevent intermediate commits to invoke commit order. | ||
| 18869 | */ | ||
| 18870 |
1/2✓ Branch 0 taken 13455 times.
✗ Branch 1 not taken.
|
13455 | Implicit_substatement_state_guard substatement_guard(thd); |
| 18871 |
2/4✓ Branch 0 taken 13455 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 13455 times.
|
13455 | if (ha_enable_transaction(thd, true)) return true; |
| 18872 | |||
| 18873 | /* | ||
| 18874 | Ensure that the new table is saved properly to disk before installing | ||
| 18875 | the new .frm. | ||
| 18876 | And that InnoDB's internal latches are released, to avoid deadlock | ||
| 18877 | when waiting on other instances of the table before rename (Bug#54747). | ||
| 18878 | */ | ||
| 18879 |
2/4✓ Branch 0 taken 13455 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 13455 times.
|
13455 | if (trans_commit_stmt(thd)) error = true; |
| 18880 |
2/4✓ Branch 0 taken 13455 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 13455 times.
|
13455 | if (trans_commit_implicit(thd)) error = true; |
| 18881 | |||
| 18882 | 13455 | return error; | |
| 18883 | 13455 | } | |
| 18884 | |||
| 18885 | 20471 | static int copy_data_between_tables( | |
| 18886 | THD *thd, PSI_stage_progress *psi [[maybe_unused]], TABLE *from, TABLE *to, | ||
| 18887 | List<Create_field> &create, ha_rows *copied, ha_rows *deleted, | ||
| 18888 | Alter_info::enum_enable_or_disable keys_onoff, Alter_table_ctx *alter_ctx, | ||
| 18889 | bool expand_fast_index_creation) { | ||
| 18890 |
1/2✓ Branch 0 taken 20471 times.
✗ Branch 1 not taken.
|
20471 | DBUG_TRACE; |
| 18891 | |||
| 18892 | int error; | ||
| 18893 | Copy_field *copy, *copy_end; | ||
| 18894 | Field **ptr; | ||
| 18895 | /* | ||
| 18896 | Fields which values need to be generated for each row, i.e. either | ||
| 18897 | generated fields or newly added fields with generated default values. | ||
| 18898 | */ | ||
| 18899 | Field **gen_fields, **gen_fields_end; | ||
| 18900 | 20471 | bool auto_increment_field_copied = false; | |
| 18901 | sql_mode_t save_sql_mode; | ||
| 18902 | 20471 | Query_expression *const unit = thd->lex->unit; | |
| 18903 | 20471 | Query_block *const select = unit->first_query_block(); | |
| 18904 | |||
| 18905 | /* | ||
| 18906 | If target storage engine supports atomic DDL we should not commit | ||
| 18907 | and disable transaction to let SE do proper cleanup on error/crash. | ||
| 18908 | Such engines should be smart enough to disable undo/redo logging | ||
| 18909 | for target table automatically. | ||
| 18910 | Temporary tables path doesn't employ atomic DDL support so disabling | ||
| 18911 | transaction is OK. Moreover doing so allows to not interfere with | ||
| 18912 | concurrent FLUSH TABLES WITH READ LOCK. | ||
| 18913 | */ | ||
| 18914 | 49002 | if ((!(to->file->ht->flags & HTON_SUPPORTS_ATOMIC_DDL) || | |
| 18915 |
5/6✓ Branch 0 taken 8060 times.
✓ Branch 1 taken 12411 times.
✓ Branch 2 taken 1050 times.
✓ Branch 3 taken 7010 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 20471 times.
|
33932 | from->s->tmp_table) && |
| 18916 |
2/4✓ Branch 0 taken 13461 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 13461 times.
|
13461 | mysql_trans_prepare_alter_copy_data(thd)) |
| 18917 | ✗ | return -1; | |
| 18918 | |||
| 18919 |
6/10✓ Branch 0 taken 20471 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20471 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 108508 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 108508 times.
✓ Branch 7 taken 20471 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 20471 times.
|
128979 | if (!(copy = new (thd->mem_root) Copy_field[to->s->fields])) |
| 18920 | ✗ | return -1; /* purecov: inspected */ | |
| 18921 | |||
| 18922 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20471 times.
|
20471 | if (!(gen_fields = thd->mem_root->ArrayAlloc<Field *>( |
| 18923 |
1/2✓ Branch 0 taken 20471 times.
✗ Branch 1 not taken.
|
20471 | to->s->gen_def_field_count + to->s->vfields))) { |
| 18924 | ✗ | destroy_array(copy, to->s->fields); | |
| 18925 | ✗ | return -1; | |
| 18926 | } | ||
| 18927 | |||
| 18928 |
2/4✓ Branch 0 taken 20471 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 20471 times.
|
20471 | if (to->file->ha_external_lock(thd, F_WRLCK)) { |
| 18929 | ✗ | destroy_array(copy, to->s->fields); | |
| 18930 | ✗ | return -1; | |
| 18931 | } | ||
| 18932 | |||
| 18933 | /* We need external lock before we can disable/enable keys */ | ||
| 18934 |
2/4✓ Branch 0 taken 20471 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20471 times.
✗ Branch 3 not taken.
|
20471 | alter_table_manage_keys(thd, to, from->file->indexes_are_disabled(), |
| 18935 | keys_onoff); | ||
| 18936 | |||
| 18937 |
2/2✓ Branch 0 taken 5277 times.
✓ Branch 1 taken 15194 times.
|
20471 | if (unit->is_prepared()) { |
| 18938 |
1/2✓ Branch 0 taken 5277 times.
✗ Branch 1 not taken.
|
5277 | bind_fields(thd->stmt_arena->item_list()); |
| 18939 | } | ||
| 18940 | /* | ||
| 18941 | We want warnings/errors about data truncation emitted when we | ||
| 18942 | copy data to new version of table. | ||
| 18943 | */ | ||
| 18944 | 20471 | thd->check_for_truncated_fields = CHECK_FIELD_WARN; | |
| 18945 | 20471 | thd->num_truncated_fields = 0L; | |
| 18946 | |||
| 18947 |
1/2✓ Branch 0 taken 20471 times.
✗ Branch 1 not taken.
|
20471 | from->file->info(HA_STATUS_VARIABLE); |
| 18948 |
1/2✓ Branch 0 taken 20471 times.
✗ Branch 1 not taken.
|
20471 | to->file->ha_start_bulk_insert(from->file->stats.records); |
| 18949 | |||
| 18950 | 20471 | mysql_stage_set_work_estimated(psi, from->file->stats.records); | |
| 18951 | |||
| 18952 | 20471 | save_sql_mode = thd->variables.sql_mode; | |
| 18953 | |||
| 18954 |
1/2✓ Branch 0 taken 20471 times.
✗ Branch 1 not taken.
|
20471 | List_iterator<Create_field> it(create); |
| 18955 | const Create_field *def; | ||
| 18956 | 20471 | copy_end = copy; | |
| 18957 | 20471 | gen_fields_end = gen_fields; | |
| 18958 |
2/2✓ Branch 0 taken 108508 times.
✓ Branch 1 taken 20471 times.
|
128979 | for (ptr = to->field; *ptr; ptr++) { |
| 18959 | 108508 | def = it++; | |
| 18960 |
2/2✓ Branch 0 taken 4524 times.
✓ Branch 1 taken 103984 times.
|
108508 | if ((*ptr)->is_gcol()) { |
| 18961 | /* | ||
| 18962 | Values in generated columns need to be (re)generated even for | ||
| 18963 | pre-existing columns, as they might depend on other columns, | ||
| 18964 | values in which might have changed as result of this ALTER. | ||
| 18965 | Because of this there is no sense in copying old values for | ||
| 18966 | these columns. | ||
| 18967 | TODO: Figure out if we can avoid even reading these old values | ||
| 18968 | from SE. | ||
| 18969 | */ | ||
| 18970 | 4524 | *(gen_fields_end++) = *ptr; | |
| 18971 | 4524 | continue; | |
| 18972 | } | ||
| 18973 | // Array fields will be properly generated during GC update loop below | ||
| 18974 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 103984 times.
|
103984 | assert(!def->is_array); |
| 18975 |
2/2✓ Branch 0 taken 100285 times.
✓ Branch 1 taken 3699 times.
|
103984 | if (def->field) { |
| 18976 |
2/2✓ Branch 0 taken 643 times.
✓ Branch 1 taken 99642 times.
|
100285 | if (*ptr == to->next_number_field) { |
| 18977 | 643 | auto_increment_field_copied = true; | |
| 18978 | /* | ||
| 18979 | If we are going to copy contents of one auto_increment column to | ||
| 18980 | another auto_increment column it is sensible to preserve zeroes. | ||
| 18981 | This condition also covers case when we are don't actually alter | ||
| 18982 | auto_increment column. | ||
| 18983 | */ | ||
| 18984 |
2/2✓ Branch 0 taken 596 times.
✓ Branch 1 taken 47 times.
|
643 | if (def->field == from->found_next_number_field) |
| 18985 | 596 | thd->variables.sql_mode |= MODE_NO_AUTO_VALUE_ON_ZERO; | |
| 18986 | } | ||
| 18987 |
1/2✓ Branch 0 taken 100285 times.
✗ Branch 1 not taken.
|
100285 | (copy_end++)->set(*ptr, def->field); |
| 18988 | } else { | ||
| 18989 | /* | ||
| 18990 | New column. Add it to the array of columns requiring value | ||
| 18991 | generation if it has generated default. | ||
| 18992 | */ | ||
| 18993 |
2/2✓ Branch 0 taken 97 times.
✓ Branch 1 taken 3602 times.
|
3699 | if ((*ptr)->has_insert_default_general_value_expression()) { |
| 18994 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 97 times.
|
97 | assert(!((*ptr)->is_gcol())); |
| 18995 | 97 | *(gen_fields_end++) = *ptr; | |
| 18996 | } | ||
| 18997 | } | ||
| 18998 | } | ||
| 18999 | |||
| 19000 | 20471 | ulong found_count = 0; | |
| 19001 | 20471 | ulong delete_count = 0; | |
| 19002 | |||
| 19003 | 20471 | ORDER *order = select->order_list.first; | |
| 19004 | |||
| 19005 | 20471 | unique_ptr_destroy_only<Filesort> fsort; | |
| 19006 | 20471 | unique_ptr_destroy_only<RowIterator> iterator; | |
| 19007 | AccessPath *path = | ||
| 19008 |
1/2✓ Branch 0 taken 20471 times.
✗ Branch 1 not taken.
|
20471 | create_table_access_path(thd, from, nullptr, nullptr, nullptr, |
| 19009 | /*count_examined_rows=*/false); | ||
| 19010 | |||
| 19011 |
6/6✓ Branch 0 taken 59 times.
✓ Branch 1 taken 20412 times.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 43 times.
✓ Branch 4 taken 10 times.
✓ Branch 5 taken 20461 times.
|
20487 | if (order != nullptr && to->s->primary_key != MAX_KEY && |
| 19012 |
3/4✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 6 times.
|
16 | to->file->primary_key_is_clustered()) { |
| 19013 | char warn_buff[MYSQL_ERRMSG_SIZE]; | ||
| 19014 | 10 | snprintf(warn_buff, sizeof(warn_buff), | |
| 19015 | "ORDER BY ignored as there is a user-defined clustered index" | ||
| 19016 | " in the table '%-.192s'", | ||
| 19017 | 10 | from->s->table_name.str); | |
| 19018 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | push_warning(thd, Sql_condition::SL_WARNING, ER_UNKNOWN_ERROR, warn_buff); |
| 19019 | 10 | order = nullptr; | |
| 19020 | } | ||
| 19021 | /* Tell handler that we have values for all columns in the to table */ | ||
| 19022 |
1/2✓ Branch 0 taken 20471 times.
✗ Branch 1 not taken.
|
20471 | to->use_all_columns(); |
| 19023 |
2/2✓ Branch 0 taken 49 times.
✓ Branch 1 taken 20422 times.
|
20471 | if (order != nullptr) { |
| 19024 |
1/2✓ Branch 0 taken 49 times.
✗ Branch 1 not taken.
|
49 | TABLE_LIST tables; |
| 19025 | 49 | tables.table = from; | |
| 19026 | 49 | tables.alias = tables.table_name = from->s->table_name.str; | |
| 19027 | 49 | tables.db = from->s->db.str; | |
| 19028 | 49 | error = 1; | |
| 19029 | |||
| 19030 |
1/2✓ Branch 0 taken 49 times.
✗ Branch 1 not taken.
|
49 | if (!unit->is_prepared()) { |
| 19031 | 49 | Column_privilege_tracker column_privilege(thd, SELECT_ACL); | |
| 19032 |
2/4✓ Branch 0 taken 49 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 49 times.
|
49 | if (select->setup_base_ref_items(thd)) { |
| 19033 | ✗ | goto err; /* purecov: inspected */ | |
| 19034 | } | ||
| 19035 | 49 | mem_root_deque<Item *> fields(thd->mem_root); | |
| 19036 |
3/4✓ Branch 0 taken 49 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 48 times.
|
49 | if (setup_order(thd, select->base_ref_items, &tables, &fields, order)) |
| 19037 | 1 | goto err; | |
| 19038 |
4/4✓ Branch 0 taken 48 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 48 times.
✓ Branch 3 taken 1 times.
|
50 | } |
| 19039 |
1/2✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
|
96 | fsort.reset(new (thd->mem_root) Filesort( |
| 19040 | thd, {from}, /*keep_buffers=*/false, order, HA_POS_ERROR, | ||
| 19041 | /*remove_duplicates=*/false, /*force_sort_rowids=*/true, | ||
| 19042 |
2/4✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 48 times.
✗ Branch 3 not taken.
|
48 | /*unwrap_rollup=*/false)); |
| 19043 |
1/2✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
|
48 | path = NewSortAccessPath(thd, path, fsort.get(), |
| 19044 | /*count_examined_rows=*/false); | ||
| 19045 | } | ||
| 19046 | |||
| 19047 |
3/4✓ Branch 0 taken 15193 times.
✓ Branch 1 taken 5277 times.
✓ Branch 2 taken 15193 times.
✗ Branch 3 not taken.
|
20470 | if (!unit->is_prepared()) unit->set_prepared(); |
| 19048 | |||
| 19049 |
1/2✓ Branch 0 taken 20470 times.
✗ Branch 1 not taken.
|
40940 | iterator = CreateIteratorFromAccessPath(thd, path, /*join=*/nullptr, |
| 19050 | 20470 | /*eligible_for_batch_mode=*/true); | |
| 19051 | // Prevent cleanup in QEP_shared_owner::qs_cleanup(), | ||
| 19052 | // to avoid double-destroy of the SortingIterator. | ||
| 19053 | 20470 | from->sorting_iterator = nullptr; | |
| 19054 |
4/8✓ Branch 0 taken 20470 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 20470 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 20470 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 20470 times.
|
20470 | if (iterator == nullptr || iterator->Init()) { |
| 19055 | ✗ | error = 1; | |
| 19056 | ✗ | goto err; | |
| 19057 | } | ||
| 19058 | 20470 | thd->get_stmt_da()->reset_current_row_for_condition(); | |
| 19059 | |||
| 19060 |
1/2✓ Branch 0 taken 20470 times.
✗ Branch 1 not taken.
|
20470 | set_column_static_defaults(to, create); |
| 19061 | |||
| 19062 |
3/4✓ Branch 0 taken 3228190 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3208670 times.
✓ Branch 3 taken 19520 times.
|
3228190 | while (!(error = iterator->Read())) { |
| 19063 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3208670 times.
|
3208670 | if (thd->killed) { |
| 19064 | ✗ | thd->send_kill_message(); | |
| 19065 | ✗ | error = 1; | |
| 19066 | ✗ | break; | |
| 19067 | } | ||
| 19068 | /* | ||
| 19069 | Return error if source table isn't empty. | ||
| 19070 | |||
| 19071 | For a DATE/DATETIME field, return error only if strict mode | ||
| 19072 | and No ZERO DATE mode is enabled. | ||
| 19073 | */ | ||
| 19074 | 6417340 | if ((alter_ctx->error_if_not_empty & | |
| 19075 |
4/4✓ Branch 0 taken 3208665 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 3208657 times.
|
6417335 | Alter_table_ctx::GEOMETRY_WITHOUT_DEFAULT) || |
| 19076 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 3208654 times.
|
3208665 | ((alter_ctx->error_if_not_empty & |
| 19077 | 11 | Alter_table_ctx::DATETIME_WITHOUT_DEFAULT) && | |
| 19078 |
4/4✓ Branch 0 taken 9 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 1 times.
|
20 | (thd->variables.sql_mode & MODE_NO_ZERO_DATE) && |
| 19079 | 9 | thd->is_strict_mode())) { | |
| 19080 | 13 | error = 1; | |
| 19081 | 13 | break; | |
| 19082 | } | ||
| 19083 |
2/2✓ Branch 0 taken 195491 times.
✓ Branch 1 taken 3013166 times.
|
3208657 | if (to->next_number_field) { |
| 19084 |
2/2✓ Branch 0 taken 195367 times.
✓ Branch 1 taken 124 times.
|
195491 | if (auto_increment_field_copied) |
| 19085 | 195367 | to->autoinc_field_has_explicit_non_null_value = true; | |
| 19086 | else | ||
| 19087 |
1/2✓ Branch 0 taken 124 times.
✗ Branch 1 not taken.
|
124 | to->next_number_field->reset(); |
| 19088 | } | ||
| 19089 | |||
| 19090 |
2/2✓ Branch 0 taken 9342019 times.
✓ Branch 1 taken 3208657 times.
|
12550676 | for (Copy_field *copy_ptr = copy; copy_ptr != copy_end; copy_ptr++) { |
| 19091 |
1/2✓ Branch 0 taken 9342019 times.
✗ Branch 1 not taken.
|
9342019 | copy_ptr->invoke_do_copy(); |
| 19092 | } | ||
| 19093 |
3/4✓ Branch 0 taken 3208657 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 37 times.
✓ Branch 3 taken 3208620 times.
|
3208657 | if (thd->is_error()) { |
| 19094 | 37 | error = 1; | |
| 19095 | 37 | break; | |
| 19096 | } | ||
| 19097 | |||
| 19098 | /* | ||
| 19099 | Iterate through all generated columns and all new columns which have | ||
| 19100 | generated defaults and evaluate their values. This needs to happen | ||
| 19101 | after copying values for old columns and storing default values for | ||
| 19102 | new columns without generated defaults, as generated values might | ||
| 19103 | depend on these values. | ||
| 19104 | OTOH generated columns/generated defaults need to be processed in | ||
| 19105 | the order in which their columns are present in table as generated | ||
| 19106 | values are allowed to depend on each other as long as there are no | ||
| 19107 | forward references (i.e. references to other columns with generated | ||
| 19108 | values which come later in the table). | ||
| 19109 | */ | ||
| 19110 |
2/2✓ Branch 0 taken 1475 times.
✓ Branch 1 taken 3208577 times.
|
3210052 | for (ptr = gen_fields; ptr != gen_fields_end; ptr++) { |
| 19111 | Item *expr_item; | ||
| 19112 |
2/2✓ Branch 0 taken 1271 times.
✓ Branch 1 taken 204 times.
|
1475 | if ((*ptr)->is_gcol()) { |
| 19113 | 1271 | expr_item = (*ptr)->gcol_info->expr_item; | |
| 19114 | } else { | ||
| 19115 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 204 times.
|
204 | assert((*ptr)->has_insert_default_general_value_expression()); |
| 19116 | 204 | expr_item = (*ptr)->m_default_val_expr->expr_item; | |
| 19117 | } | ||
| 19118 |
1/2✓ Branch 0 taken 1475 times.
✗ Branch 1 not taken.
|
1475 | expr_item->save_in_field(*ptr, false); |
| 19119 |
3/4✓ Branch 0 taken 1475 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 43 times.
✓ Branch 3 taken 1432 times.
|
1475 | if (thd->is_error()) { |
| 19120 | 43 | error = 1; | |
| 19121 | 43 | break; | |
| 19122 | } | ||
| 19123 | } | ||
| 19124 |
2/2✓ Branch 0 taken 43 times.
✓ Branch 1 taken 3208577 times.
|
3208620 | if (error) break; |
| 19125 | |||
| 19126 |
1/2✓ Branch 0 taken 3208576 times.
✗ Branch 1 not taken.
|
3208577 | error = invoke_table_check_constraints(thd, to); |
| 19127 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 3208562 times.
|
3208576 | if (error) break; |
| 19128 | |||
| 19129 |
1/2✓ Branch 0 taken 3208562 times.
✗ Branch 1 not taken.
|
3208562 | error = to->file->ha_write_row(to->record[0]); |
| 19130 | 3208562 | to->autoinc_field_has_explicit_non_null_value = false; | |
| 19131 |
2/2✓ Branch 0 taken 843 times.
✓ Branch 1 taken 3207719 times.
|
3208562 | if (error) { |
| 19132 |
3/4✓ Branch 0 taken 843 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 839 times.
|
843 | if (!to->file->is_ignorable_error(error)) { |
| 19133 | /* Not a duplicate key error. */ | ||
| 19134 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | to->file->print_error(error, MYF(0)); |
| 19135 | 4 | break; | |
| 19136 |
2/4✓ Branch 0 taken 839 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 839 times.
✗ Branch 3 not taken.
|
839 | } else if (!to->file->continue_partition_copying_on_error(error)) { |
| 19137 | /* Report duplicate key error. */ | ||
| 19138 |
1/2✓ Branch 0 taken 839 times.
✗ Branch 1 not taken.
|
839 | uint key_nr = to->file->get_dup_key(error); |
| 19139 |
2/2✓ Branch 0 taken 836 times.
✓ Branch 1 taken 3 times.
|
839 | if ((int)key_nr >= 0) { |
| 19140 |
1/2✓ Branch 0 taken 836 times.
✗ Branch 1 not taken.
|
836 | const char *err_msg = ER_THD(thd, ER_DUP_ENTRY_WITH_KEY_NAME); |
| 19141 |
6/6✓ Branch 0 taken 35 times.
✓ Branch 1 taken 801 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 34 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 835 times.
|
836 | if (key_nr == 0 && (to->key_info[0].key_part[0].field->is_flag_set( |
| 19142 | AUTO_INCREMENT_FLAG))) | ||
| 19143 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | err_msg = ER_THD(thd, ER_DUP_ENTRY_AUTOINCREMENT_CASE); |
| 19144 |
1/2✓ Branch 0 taken 836 times.
✗ Branch 1 not taken.
|
836 | print_keydup_error( |
| 19145 | 836 | to, key_nr == MAX_KEY ? nullptr : &to->key_info[key_nr], err_msg, | |
| 19146 |
1/2✓ Branch 0 taken 836 times.
✗ Branch 1 not taken.
|
836 | MYF(0), from->s->table_name.str); |
| 19147 | } else | ||
| 19148 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | to->file->print_error(error, MYF(0)); |
| 19149 | 839 | break; | |
| 19150 | } | ||
| 19151 | } else { | ||
| 19152 |
3/4✓ Branch 0 taken 3207536 times.
✓ Branch 1 taken 182 times.
✓ Branch 2 taken 3207538 times.
✗ Branch 3 not taken.
|
3207719 | DEBUG_SYNC(thd, "copy_data_between_tables_before"); |
| 19153 | 3207720 | found_count++; | |
| 19154 | 3207720 | mysql_stage_set_work_completed(psi, found_count); | |
| 19155 | } | ||
| 19156 | 3207718 | thd->get_stmt_da()->inc_current_row_for_condition(); | |
| 19157 | } | ||
| 19158 | 20470 | iterator.reset(); | |
| 19159 |
1/2✓ Branch 0 taken 20470 times.
✗ Branch 1 not taken.
|
20470 | free_io_cache(from); |
| 19160 | |||
| 19161 |
3/4✓ Branch 0 taken 20277 times.
✓ Branch 1 taken 193 times.
✓ Branch 2 taken 20277 times.
✗ Branch 3 not taken.
|
20470 | DEBUG_SYNC(thd, "after_copy_data_between_tables"); |
| 19162 | |||
| 19163 |
3/8✓ Branch 0 taken 20470 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 20470 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 20470 times.
|
20470 | if (to->file->ha_end_bulk_insert() && error <= 0) { |
| 19164 | ✗ | to->file->print_error(my_errno(), MYF(0)); | |
| 19165 | ✗ | error = 1; | |
| 19166 | } | ||
| 19167 | |||
| 19168 |
4/6✓ Branch 0 taken 20470 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 20468 times.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
20470 | DBUG_EXECUTE_IF("crash_copy_before_commit", DBUG_SUICIDE();); |
| 19169 | |||
| 19170 | /* This code commits the entire transaction (both trans_commit_stmt() | ||
| 19171 | and trans_commit_implicit()) for engines that don't support atomic DDL | ||
| 19172 | and for all temporary tables(independent of engine type) | ||
| 19173 | |||
| 19174 | When expanded fast index creation is enabled, after copy data stage, | ||
| 19175 | there are inplace alters to add removed secondary indexes. Thus we | ||
| 19176 | need to commit the transaction again. A full commit here would make | ||
| 19177 | all future trans_commit_stmt() and trans_commit_implicit() to be dummy | ||
| 19178 | and we would leave transaction open. | ||
| 19179 | |||
| 19180 | With 8.0, this code looks irrevelant for temporary tables but we play | ||
| 19181 | safe and disable intermediate commit only for temporary tables when | ||
| 19182 | expanded fast index creation is enabled */ | ||
| 19183 | 48994 | if ((!(to->file->ht->flags & HTON_SUPPORTS_ATOMIC_DDL) || | |
| 19184 |
7/8✓ Branch 0 taken 8058 times.
✓ Branch 1 taken 12410 times.
✓ Branch 2 taken 1050 times.
✓ Branch 3 taken 7008 times.
✓ Branch 4 taken 1045 times.
✓ Branch 5 taken 5 times.
✓ Branch 6 taken 20468 times.
✗ Branch 7 not taken.
|
33923 | (from->s->tmp_table && !expand_fast_index_creation)) && |
| 19185 |
2/4✓ Branch 0 taken 13455 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 13455 times.
|
13455 | mysql_trans_commit_alter_copy_data(thd)) |
| 19186 | ✗ | error = 1; | |
| 19187 | |||
| 19188 | 20468 | err: | |
| 19189 |
1/2✓ Branch 0 taken 20469 times.
✗ Branch 1 not taken.
|
20469 | destroy_array(copy, to->s->fields); |
| 19190 | 20469 | thd->variables.sql_mode = save_sql_mode; | |
| 19191 |
1/2✓ Branch 0 taken 20469 times.
✗ Branch 1 not taken.
|
20469 | free_io_cache(from); |
| 19192 | 20469 | *copied = found_count; | |
| 19193 | 20469 | *deleted = delete_count; | |
| 19194 |
1/2✓ Branch 0 taken 20469 times.
✗ Branch 1 not taken.
|
20469 | to->file->ha_release_auto_increment(); |
| 19195 |
2/4✓ Branch 0 taken 20469 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 20469 times.
|
20469 | if (to->file->ha_external_lock(thd, F_UNLCK)) error = 1; |
| 19196 |
5/8✓ Branch 0 taken 19496 times.
✓ Branch 1 taken 973 times.
✓ Branch 2 taken 19496 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 19496 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 20469 times.
|
20469 | if (error < 0 && to->file->ha_extra(HA_EXTRA_PREPARE_FOR_RENAME)) error = 1; |
| 19197 | 20469 | thd->check_for_truncated_fields = CHECK_FIELD_IGNORE; | |
| 19198 |
2/2✓ Branch 0 taken 973 times.
✓ Branch 1 taken 19496 times.
|
20469 | return error > 0 ? -1 : 0; |
| 19199 | 20469 | } | |
| 19200 | |||
| 19201 | /* | ||
| 19202 | Recreates tables by calling mysql_alter_table(). | ||
| 19203 | |||
| 19204 | SYNOPSIS | ||
| 19205 | mysql_recreate_table() | ||
| 19206 | thd Thread handler | ||
| 19207 | tables Tables to recreate | ||
| 19208 | table_copy Recreate the table by using ALTER TABLE COPY algorithm | ||
| 19209 | |||
| 19210 | RETURN | ||
| 19211 | Like mysql_alter_table(). | ||
| 19212 | */ | ||
| 19213 | 2132 | bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list, bool table_copy) { | |
| 19214 |
1/2✓ Branch 0 taken 2132 times.
✗ Branch 1 not taken.
|
2132 | HA_CREATE_INFO create_info; |
| 19215 |
1/2✓ Branch 0 taken 2132 times.
✗ Branch 1 not taken.
|
2132 | Alter_info alter_info(thd->mem_root); |
| 19216 | |||
| 19217 |
1/2✓ Branch 0 taken 2132 times.
✗ Branch 1 not taken.
|
2132 | DBUG_TRACE; |
| 19218 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2132 times.
|
2132 | assert(!table_list->next_global); |
| 19219 | |||
| 19220 | /* Set lock type which is appropriate for ALTER TABLE. */ | ||
| 19221 | 2132 | table_list->set_lock({TL_READ_NO_INSERT, THR_DEFAULT}); | |
| 19222 | /* Same applies to MDL request. */ | ||
| 19223 | 2132 | table_list->mdl_request.set_type(MDL_SHARED_NO_WRITE); | |
| 19224 | |||
| 19225 | 2132 | create_info.row_type = ROW_TYPE_NOT_USED; | |
| 19226 | 2132 | create_info.default_table_charset = default_charset_info; | |
| 19227 | /* Force alter table to recreate table */ | ||
| 19228 | 2132 | alter_info.flags = | |
| 19229 | (Alter_info::ALTER_CHANGE_COLUMN | Alter_info::ALTER_RECREATE); | ||
| 19230 | |||
| 19231 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2132 times.
|
2132 | if (table_copy) |
| 19232 | ✗ | alter_info.requested_algorithm = Alter_info::ALTER_TABLE_ALGORITHM_COPY; | |
| 19233 | |||
| 19234 |
1/2✓ Branch 0 taken 2112 times.
✗ Branch 1 not taken.
|
2132 | const bool ret = mysql_alter_table(thd, NullS, NullS, &create_info, |
| 19235 | table_list, &alter_info); | ||
| 19236 | 2112 | return ret; | |
| 19237 | 2112 | } | |
| 19238 | |||
| 19239 | 28041 | bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, | |
| 19240 | HA_CHECK_OPT *check_opt) { | ||
| 19241 | TABLE_LIST *table; | ||
| 19242 | Item *item; | ||
| 19243 | 28041 | Protocol *protocol = thd->get_protocol(); | |
| 19244 |
1/2✓ Branch 0 taken 28041 times.
✗ Branch 1 not taken.
|
28041 | DBUG_TRACE; |
| 19245 | |||
| 19246 | /* | ||
| 19247 | CHECKSUM TABLE returns results and rollbacks statement transaction, | ||
| 19248 | so it should not be used in stored function or trigger. | ||
| 19249 | */ | ||
| 19250 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 28041 times.
|
28041 | assert(!thd->in_sub_stmt); |
| 19251 | |||
| 19252 | 28041 | mem_root_deque<Item *> field_list(thd->mem_root); | |
| 19253 |
3/6✓ Branch 0 taken 28041 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28041 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 28041 times.
✗ Branch 5 not taken.
|
28041 | field_list.push_back(item = new Item_empty_string("Table", NAME_LEN * 2)); |
| 19254 | 28041 | item->set_nullable(true); | |
| 19255 |
2/4✓ Branch 0 taken 28041 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28041 times.
✗ Branch 3 not taken.
|
84123 | field_list.push_back(item = new Item_int(NAME_STRING("Checksum"), (longlong)1, |
| 19256 |
1/2✓ Branch 0 taken 28041 times.
✗ Branch 1 not taken.
|
56082 | MY_INT64_NUM_DECIMAL_DIGITS)); |
| 19257 | 28041 | item->set_nullable(true); | |
| 19258 |
2/4✓ Branch 0 taken 28041 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 28041 times.
|
28041 | if (thd->send_result_metadata(field_list, |
| 19259 | Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) | ||
| 19260 | ✗ | return true; | |
| 19261 | |||
| 19262 | /* | ||
| 19263 | Close all temporary tables which were pre-open to simplify | ||
| 19264 | privilege checking. Clear all references to closed tables. | ||
| 19265 | */ | ||
| 19266 |
1/2✓ Branch 0 taken 28041 times.
✗ Branch 1 not taken.
|
28041 | close_thread_tables(thd); |
| 19267 |
2/2✓ Branch 0 taken 722336 times.
✓ Branch 1 taken 28041 times.
|
750377 | for (table = tables; table; table = table->next_local) table->table = nullptr; |
| 19268 | |||
| 19269 | /* Open one table after the other to keep lock time as short as possible. */ | ||
| 19270 |
2/2✓ Branch 0 taken 722336 times.
✓ Branch 1 taken 28041 times.
|
750377 | for (table = tables; table; table = table->next_local) { |
| 19271 | char table_name[NAME_LEN * 2 + 2]; | ||
| 19272 | TABLE *t; | ||
| 19273 | TABLE_LIST *save_next_global; | ||
| 19274 | |||
| 19275 |
1/2✓ Branch 0 taken 722336 times.
✗ Branch 1 not taken.
|
722336 | strxmov(table_name, table->db, ".", table->table_name, NullS); |
| 19276 | |||
| 19277 | /* Remember old 'next' pointer and break the list. */ | ||
| 19278 | 722336 | save_next_global = table->next_global; | |
| 19279 | 722336 | table->next_global = nullptr; | |
| 19280 | 722336 | table->set_lock({TL_READ, THR_DEFAULT}); | |
| 19281 | /* Allow to open real tables only. */ | ||
| 19282 | 722336 | table->required_type = dd::enum_table_type::BASE_TABLE; | |
| 19283 | |||
| 19284 |
4/6✓ Branch 0 taken 722336 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 722336 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 722328 times.
|
1444672 | if (open_temporary_tables(thd, table) || |
| 19285 |
3/4✓ Branch 0 taken 722336 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 722328 times.
|
722336 | open_and_lock_tables(thd, table, 0)) { |
| 19286 | 8 | t = nullptr; | |
| 19287 | } else | ||
| 19288 | 722328 | t = table->table; | |
| 19289 | |||
| 19290 | 722336 | table->next_global = save_next_global; | |
| 19291 | |||
| 19292 |
1/2✓ Branch 0 taken 722336 times.
✗ Branch 1 not taken.
|
722336 | protocol->start_row(); |
| 19293 |
1/2✓ Branch 0 taken 722336 times.
✗ Branch 1 not taken.
|
722336 | protocol->store(table_name, system_charset_info); |
| 19294 | |||
| 19295 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 722328 times.
|
722336 | if (!t) { |
| 19296 | /* Table didn't exist */ | ||
| 19297 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | protocol->store_null(); |
| 19298 | } else { | ||
| 19299 |
4/4✓ Branch 0 taken 3 times.
✓ Branch 1 taken 722325 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 722326 times.
|
722331 | if (t->file->ha_table_flags() & HA_HAS_CHECKSUM && |
| 19300 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
|
3 | !(check_opt->flags & T_EXTEND)) |
| 19301 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | protocol->store((ulonglong)t->file->checksum()); |
| 19302 |
4/4✓ Branch 0 taken 722325 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 722324 times.
|
1444651 | else if (!(t->file->ha_table_flags() & HA_HAS_CHECKSUM) && |
| 19303 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 722323 times.
|
722325 | (check_opt->flags & T_QUICK)) |
| 19304 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | protocol->store_null(); |
| 19305 | else { | ||
| 19306 | /* calculating table's checksum */ | ||
| 19307 | 722324 | ha_checksum crc = 0; | |
| 19308 | 722324 | uchar null_mask = 256 - (1 << t->s->last_null_bit_pos); | |
| 19309 | |||
| 19310 |
1/2✓ Branch 0 taken 722324 times.
✗ Branch 1 not taken.
|
722324 | t->use_all_columns(); |
| 19311 | |||
| 19312 |
2/4✓ Branch 0 taken 722324 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 722324 times.
|
722324 | if (t->file->ha_rnd_init(true)) |
| 19313 | ✗ | protocol->store_null(); | |
| 19314 | else { | ||
| 19315 | for (;;) { | ||
| 19316 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 131759229 times.
|
131759229 | if (thd->killed) { |
| 19317 | /* | ||
| 19318 | we've been killed; let handler clean up, and remove the | ||
| 19319 | partial current row from the recordset (embedded lib) | ||
| 19320 | */ | ||
| 19321 | ✗ | t->file->ha_rnd_end(); | |
| 19322 | ✗ | protocol->abort_row(); | |
| 19323 | ✗ | goto err; | |
| 19324 | } | ||
| 19325 | 131759229 | ha_checksum row_crc = 0; | |
| 19326 |
1/2✓ Branch 0 taken 131759229 times.
✗ Branch 1 not taken.
|
131759229 | int error = t->file->ha_rnd_next(t->record[0]); |
| 19327 |
2/2✓ Branch 0 taken 1247606 times.
✓ Branch 1 taken 130511623 times.
|
131759229 | if (unlikely(error)) { |
| 19328 |
2/2✓ Branch 0 taken 525282 times.
✓ Branch 1 taken 722324 times.
|
1247606 | if (error == HA_ERR_RECORD_DELETED) continue; |
| 19329 | 722324 | break; | |
| 19330 | } | ||
| 19331 |
2/2✓ Branch 0 taken 3231439 times.
✓ Branch 1 taken 127280184 times.
|
130511623 | if (t->s->null_bytes) { |
| 19332 | /* fix undefined null bits */ | ||
| 19333 | 3231439 | t->record[0][t->s->null_bytes - 1] |= null_mask; | |
| 19334 |
2/2✓ Branch 0 taken 1573239 times.
✓ Branch 1 taken 1658200 times.
|
3231439 | if (!(t->s->db_create_options & HA_OPTION_PACK_RECORD)) |
| 19335 | 1573239 | t->record[0][0] |= 1; | |
| 19336 | |||
| 19337 |
1/2✓ Branch 0 taken 3231439 times.
✗ Branch 1 not taken.
|
3231439 | row_crc = checksum_crc32(row_crc, t->record[0], t->s->null_bytes); |
| 19338 | } | ||
| 19339 | |||
| 19340 |
2/2✓ Branch 0 taken 375369488 times.
✓ Branch 1 taken 130511623 times.
|
505881111 | for (uint i = 0; i < t->s->fields; i++) { |
| 19341 | 375369488 | Field *f = t->field[i]; | |
| 19342 | |||
| 19343 | /* | ||
| 19344 | BLOB and VARCHAR have pointers in their field, we must convert | ||
| 19345 | to string; GEOMETRY and JSON are implemented on top of BLOB. | ||
| 19346 | BIT may store its data among NULL bits, convert as well. | ||
| 19347 | */ | ||
| 19348 |
3/4✓ Branch 0 taken 375369488 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 60912908 times.
✓ Branch 3 taken 314456580 times.
|
375369488 | switch (f->type()) { |
| 19349 | 60912908 | case MYSQL_TYPE_BLOB: | |
| 19350 | case MYSQL_TYPE_VARCHAR: | ||
| 19351 | case MYSQL_TYPE_GEOMETRY: | ||
| 19352 | case MYSQL_TYPE_JSON: | ||
| 19353 | case MYSQL_TYPE_BIT: { | ||
| 19354 | 60912908 | String tmp; | |
| 19355 |
1/2✓ Branch 0 taken 60912908 times.
✗ Branch 1 not taken.
|
60912908 | f->val_str(&tmp); |
| 19356 | row_crc = | ||
| 19357 |
1/2✓ Branch 0 taken 60912908 times.
✗ Branch 1 not taken.
|
60912908 | checksum_crc32(row_crc, (uchar *)tmp.ptr(), tmp.length()); |
| 19358 | 60912908 | break; | |
| 19359 | 60912908 | } | |
| 19360 | 314456580 | default: | |
| 19361 | row_crc = | ||
| 19362 |
2/4✓ Branch 0 taken 314456580 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 314456580 times.
✗ Branch 3 not taken.
|
314456580 | checksum_crc32(row_crc, f->field_ptr(), f->pack_length()); |
| 19363 | 314456580 | break; | |
| 19364 | } | ||
| 19365 | } | ||
| 19366 | |||
| 19367 | 130511623 | crc += row_crc; | |
| 19368 | 131036905 | } | |
| 19369 |
1/2✓ Branch 0 taken 722324 times.
✗ Branch 1 not taken.
|
722324 | protocol->store((ulonglong)crc); |
| 19370 |
1/2✓ Branch 0 taken 722324 times.
✗ Branch 1 not taken.
|
722324 | t->file->ha_rnd_end(); |
| 19371 | } | ||
| 19372 | } | ||
| 19373 |
1/2✓ Branch 0 taken 722328 times.
✗ Branch 1 not taken.
|
722328 | trans_rollback_stmt(thd); |
| 19374 |
1/2✓ Branch 0 taken 722328 times.
✗ Branch 1 not taken.
|
722328 | close_thread_tables(thd); |
| 19375 | } | ||
| 19376 | |||
| 19377 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 722336 times.
|
722336 | if (thd->transaction_rollback_request) { |
| 19378 | /* | ||
| 19379 | If transaction rollback was requested we honor it. To do this we | ||
| 19380 | abort statement and return error as not only CHECKSUM TABLE is | ||
| 19381 | rolled back but the whole transaction in which it was used. | ||
| 19382 | */ | ||
| 19383 | ✗ | protocol->abort_row(); | |
| 19384 | ✗ | goto err; | |
| 19385 | } | ||
| 19386 | |||
| 19387 | /* Hide errors from client. Return NULL for problematic tables instead. */ | ||
| 19388 |
1/2✓ Branch 0 taken 722336 times.
✗ Branch 1 not taken.
|
722336 | thd->clear_error(); |
| 19389 | |||
| 19390 |
2/4✓ Branch 0 taken 722336 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 722336 times.
|
722336 | if (protocol->end_row()) goto err; |
| 19391 | } | ||
| 19392 | |||
| 19393 |
1/2✓ Branch 0 taken 28041 times.
✗ Branch 1 not taken.
|
28041 | my_eof(thd); |
| 19394 | 28041 | return false; | |
| 19395 | |||
| 19396 | ✗ | err: | |
| 19397 | ✗ | return true; | |
| 19398 | 28041 | } | |
| 19399 | |||
| 19400 | /** | ||
| 19401 | @brief Check if the table can be created in the specified storage engine. | ||
| 19402 | |||
| 19403 | Checks if the storage engine is enabled and supports the given table | ||
| 19404 | type (e.g. normal, temporary, system). May do engine substitution | ||
| 19405 | if the requested engine does not support temporary tables. | ||
| 19406 | |||
| 19407 | @param db_name Database name. | ||
| 19408 | @param table_name Name of table to be created. | ||
| 19409 | @param create_info Create info from parser, including engine. | ||
| 19410 | |||
| 19411 | @retval true Engine not available/supported, error has been reported. | ||
| 19412 | @retval false Engine available/supported. | ||
| 19413 | */ | ||
| 19414 | 851226 | static bool check_engine(THD *thd, const char *db_name, const char *table_name, | |
| 19415 | HA_CREATE_INFO *create_info, | ||
| 19416 | const Alter_info *alter_info) { | ||
| 19417 |
1/2✓ Branch 0 taken 851243 times.
✗ Branch 1 not taken.
|
851226 | DBUG_TRACE; |
| 19418 | 851243 | handlerton **new_engine = &create_info->db_type; | |
| 19419 | 851243 | handlerton *req_engine = *new_engine; | |
| 19420 | |||
| 19421 |
4/6✓ Branch 0 taken 218 times.
✓ Branch 1 taken 851025 times.
✓ Branch 2 taken 218 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 218 times.
✗ Branch 5 not taken.
|
851243 | if (enforce_storage_engine && !opt_initialize && !opt_noacl) { |
| 19422 | /* | ||
| 19423 | Storage engine enforcement must be forbidden: | ||
| 19424 | 1. for "OPTIMIZE TABLE" statements. | ||
| 19425 | 2. for "ALTER TABLE" statements without explicit "... ENGINE=xxx" part | ||
| 19426 | 3. Transactional data dictionary (DD) tables | ||
| 19427 | */ | ||
| 19428 | 218 | bool no_substitution = (!is_engine_substitution_allowed(thd)); | |
| 19429 | |||
| 19430 | bool enforcement_forbidden = | ||
| 19431 | 252 | ((thd->lex->sql_command == SQLCOM_ALTER_TABLE) && | |
| 19432 |
2/2✓ Branch 0 taken 22 times.
✓ Branch 1 taken 12 times.
|
34 | (create_info->used_fields & HA_CREATE_USED_ENGINE) == 0) || |
| 19433 |
2/2✓ Branch 0 taken 202 times.
✓ Branch 1 taken 4 times.
|
206 | (thd->lex->sql_command == SQLCOM_OPTIMIZE) || |
| 19434 |
8/16✓ Branch 0 taken 202 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 202 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 202 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 202 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 32 times.
✓ Branch 9 taken 170 times.
✓ Branch 10 taken 202 times.
✓ Branch 11 taken 16 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
|
420 | dd::get_dictionary()->is_dd_table_name(db_name, table_name) |
| 19435 | // Allow creation of the new redo log table | ||
| 19436 |
6/6✓ Branch 0 taken 34 times.
✓ Branch 1 taken 184 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 28 times.
✓ Branch 4 taken 202 times.
✓ Branch 5 taken 16 times.
|
436 | || (strcmp(db_name, "performance_schema") == 0); |
| 19437 | |||
| 19438 |
2/2✓ Branch 0 taken 28 times.
✓ Branch 1 taken 173 times.
|
218 | if (!enforcement_forbidden) { |
| 19439 |
1/2✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
|
28 | handlerton *enf_engine = ha_enforce_handlerton(thd); |
| 19440 |
1/2✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
|
28 | if (enf_engine) { |
| 19441 |
4/4✓ Branch 0 taken 14 times.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 5 times.
|
28 | if (enf_engine != *new_engine && no_substitution) { |
| 19442 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
9 | const char *engine_name = ha_resolve_storage_engine_name(req_engine); |
| 19443 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
9 | my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), engine_name, engine_name); |
| 19444 | 9 | return true; | |
| 19445 | } | ||
| 19446 | 19 | *new_engine = enf_engine; | |
| 19447 | } | ||
| 19448 | } | ||
| 19449 | } | ||
| 19450 | |||
| 19451 | /* | ||
| 19452 | Check, if the given table name is system table, and if the storage engine | ||
| 19453 | does supports it. | ||
| 19454 | */ | ||
| 19455 |
4/4✓ Branch 0 taken 557851 times.
✓ Branch 1 taken 293366 times.
✓ Branch 2 taken 85 times.
✓ Branch 3 taken 851150 times.
|
1409086 | if ((create_info->used_fields & HA_CREATE_USED_ENGINE) && |
| 19456 |
3/4✓ Branch 0 taken 557869 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 85 times.
✓ Branch 3 taken 557784 times.
|
557851 | !ha_check_if_supported_system_table(*new_engine, db_name, table_name)) { |
| 19457 |
2/4✓ Branch 0 taken 85 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 85 times.
✗ Branch 3 not taken.
|
85 | my_error(ER_UNSUPPORTED_ENGINE, MYF(0), |
| 19458 | ha_resolve_storage_engine_name(*new_engine), db_name, table_name); | ||
| 19459 | 85 | *new_engine = nullptr; | |
| 19460 | 85 | return true; | |
| 19461 | } | ||
| 19462 | /* | ||
| 19463 | Check if the given table has compressed columns, and if the storage engine | ||
| 19464 | does support it. | ||
| 19465 | */ | ||
| 19466 | 851150 | partition_info *part_info = thd->work_part_info; | |
| 19467 | bool check_compressed_columns = | ||
| 19468 |
2/2✓ Branch 0 taken 843031 times.
✓ Branch 1 taken 8119 times.
|
1694177 | part_info == 0 && |
| 19469 |
2/2✓ Branch 0 taken 709636 times.
✓ Branch 1 taken 133395 times.
|
843031 | !(create_info->db_type->partition_flags && |
| 19470 |
2/4✓ Branch 0 taken 709632 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 709633 times.
✗ Branch 3 not taken.
|
709636 | (create_info->db_type->partition_flags() & HA_USE_AUTO_PARTITION)); |
| 19471 | |||
| 19472 |
7/8✓ Branch 0 taken 843029 times.
✓ Branch 1 taken 8117 times.
✓ Branch 2 taken 843032 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 292 times.
✓ Branch 5 taken 842740 times.
✓ Branch 6 taken 10 times.
✓ Branch 7 taken 851139 times.
|
851438 | if (check_compressed_columns && alter_info->has_compressed_columns() && |
| 19473 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 282 times.
|
292 | !ha_check_storage_engine_flag(*new_engine, |
| 19474 | HTON_SUPPORTS_COMPRESSED_COLUMNS)) { | ||
| 19475 |
2/4✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
|
10 | my_error(ER_ILLEGAL_HA_CREATE_OPTION, MYF(0), |
| 19476 | ha_resolve_storage_engine_name(*new_engine), "COMPRESSED COLUMNS"); | ||
| 19477 | 10 | *new_engine = 0; | |
| 19478 | 10 | return true; | |
| 19479 | } | ||
| 19480 | |||
| 19481 | // The storage engine must support secondary engines. | ||
| 19482 |
2/2✓ Branch 0 taken 211 times.
✓ Branch 1 taken 850928 times.
|
851139 | if (create_info->used_fields & HA_CREATE_USED_SECONDARY_ENGINE && |
| 19483 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 210 times.
|
211 | !((*new_engine)->flags & HTON_SUPPORTS_SECONDARY_ENGINE)) { |
| 19484 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "SECONDARY_ENGINE"); |
| 19485 | 1 | return true; | |
| 19486 | } | ||
| 19487 | |||
| 19488 | // The storage engine must support encryption. | ||
| 19489 |
2/2✓ Branch 0 taken 94315 times.
✓ Branch 1 taken 756823 times.
|
851138 | if (create_info->encrypt_type.str) { |
| 19490 | 94315 | bool encryption_request_type = false; | |
| 19491 | 94315 | dd::String_type encrypt_type; | |
| 19492 |
1/2✓ Branch 0 taken 94326 times.
✗ Branch 1 not taken.
|
94325 | encrypt_type.assign(create_info->encrypt_type.str, |
| 19493 | create_info->encrypt_type.length); | ||
| 19494 |
1/2✓ Branch 0 taken 94327 times.
✗ Branch 1 not taken.
|
94326 | encryption_request_type = is_encrypted(encrypt_type); |
| 19495 |
2/2✓ Branch 0 taken 7969 times.
✓ Branch 1 taken 86358 times.
|
94327 | if (encryption_request_type && |
| 19496 |
2/2✓ Branch 0 taken 34 times.
✓ Branch 1 taken 7935 times.
|
7969 | !((*new_engine)->flags & HTON_SUPPORTS_TABLE_ENCRYPTION)) { |
| 19497 |
1/2✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
|
34 | my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "ENCRYPTION"); |
| 19498 | 34 | return true; | |
| 19499 | } | ||
| 19500 |
2/2✓ Branch 0 taken 94293 times.
✓ Branch 1 taken 34 times.
|
94327 | } |
| 19501 | |||
| 19502 | 851116 | return false; | |
| 19503 | 851255 | } | |
| 19504 | |||
| 19505 | /** | ||
| 19506 | Helper method to generate check constraint name. | ||
| 19507 | |||
| 19508 | @param thd Thread handle. | ||
| 19509 | @param table_name Table name. | ||
| 19510 | @param ordinal_number Ordinal number of the generated name. | ||
| 19511 | @param[out] name LEX_STRING instance to hold the | ||
| 19512 | generated check constraint name. | ||
| 19513 | @param skip_validation Skip generated name validation. | ||
| 19514 | */ | ||
| 19515 | 320 | static bool generate_check_constraint_name(THD *thd, const char *table_name, | |
| 19516 | uint ordinal_number, | ||
| 19517 | LEX_STRING &name, | ||
| 19518 | bool skip_validation) { | ||
| 19519 | // Allocate memory for name. | ||
| 19520 | 320 | size_t generated_name_len = | |
| 19521 | 320 | strlen(table_name) + sizeof(dd::CHECK_CONSTRAINT_NAME_SUBSTR) + 11 + 1; | |
| 19522 | 320 | name.str = (char *)thd->mem_root->Alloc(generated_name_len); | |
| 19523 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 320 times.
|
320 | if (name.str == nullptr) return true; // OOM |
| 19524 | |||
| 19525 | // Prepare name for check constraint. | ||
| 19526 | 320 | sprintf(name.str, "%s%s%u", table_name, dd::CHECK_CONSTRAINT_NAME_SUBSTR, | |
| 19527 | ordinal_number); | ||
| 19528 | 320 | name.length = strlen(name.str); | |
| 19529 | |||
| 19530 | // Validate check constraint name. | ||
| 19531 |
2/2✓ Branch 0 taken 281 times.
✓ Branch 1 taken 39 times.
|
601 | if (!skip_validation && |
| 19532 |
5/6✓ Branch 0 taken 281 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 279 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 318 times.
|
601 | check_string_char_length(to_lex_cstring(name), "", NAME_CHAR_LEN, |
| 19533 | system_charset_info, true)) { | ||
| 19534 | 2 | my_error(ER_TOO_LONG_IDENT, MYF(0), name.str); | |
| 19535 | 2 | return true; | |
| 19536 | } | ||
| 19537 | |||
| 19538 | 318 | return false; | |
| 19539 | } | ||
| 19540 | |||
| 19541 | /** | ||
| 19542 | Helper method to create MDL_request for check constraint names. Check | ||
| 19543 | constraint names are case insensitive. Hence names are lowercased | ||
| 19544 | in MDL_request and pushed to MDL_request_list. | ||
| 19545 | |||
| 19546 | @param thd Thread handle. | ||
| 19547 | @param db Database name. | ||
| 19548 | @param cc_name Check constraint name. | ||
| 19549 | @param[out] cc_mdl_request_list MDL request list. | ||
| 19550 | |||
| 19551 | @retval false Success. | ||
| 19552 | @retval true Failure. | ||
| 19553 | */ | ||
| 19554 | 4296 | static bool push_check_constraint_mdl_request_to_list( | |
| 19555 | THD *thd, const char *db, const char *cc_name, | ||
| 19556 | MDL_request_list &cc_mdl_request_list) { | ||
| 19557 |
3/6✓ Branch 0 taken 4296 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4296 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4296 times.
✗ Branch 5 not taken.
|
4296 | assert(thd != nullptr && db != nullptr && cc_name != nullptr); |
| 19558 | |||
| 19559 | /* | ||
| 19560 | Check constraint names are case insensitive. Hence lowercasing names for | ||
| 19561 | MDL locking. | ||
| 19562 | */ | ||
| 19563 | char lc_cc_name[NAME_LEN + 1]; | ||
| 19564 |
1/2✓ Branch 0 taken 4296 times.
✗ Branch 1 not taken.
|
4296 | strmake(lc_cc_name, cc_name, NAME_LEN); |
| 19565 |
1/2✓ Branch 0 taken 4296 times.
✗ Branch 1 not taken.
|
4296 | my_casedn_str(system_charset_info, lc_cc_name); |
| 19566 | |||
| 19567 |
1/2✓ Branch 0 taken 4296 times.
✗ Branch 1 not taken.
|
4296 | MDL_request *mdl_request = new (thd->mem_root) MDL_request; |
| 19568 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4296 times.
|
4296 | if (mdl_request == nullptr) return true; // OOM |
| 19569 |
1/2✓ Branch 0 taken 4296 times.
✗ Branch 1 not taken.
|
4296 | MDL_REQUEST_INIT(mdl_request, MDL_key::CHECK_CONSTRAINT, db, lc_cc_name, |
| 19570 | MDL_EXCLUSIVE, MDL_STATEMENT); | ||
| 19571 |
1/2✓ Branch 0 taken 4296 times.
✗ Branch 1 not taken.
|
4296 | cc_mdl_request_list.push_front(mdl_request); |
| 19572 | |||
| 19573 | 4296 | return false; | |
| 19574 | } | ||
| 19575 | |||
| 19576 | 670339 | bool prepare_check_constraints_for_create(THD *thd, const char *db_name, | |
| 19577 | const char *table_name, | ||
| 19578 | Alter_info *alter_info) { | ||
| 19579 |
1/2✓ Branch 0 taken 670344 times.
✗ Branch 1 not taken.
|
670339 | DBUG_TRACE; |
| 19580 |
1/2✓ Branch 0 taken 670343 times.
✗ Branch 1 not taken.
|
670344 | MDL_request_list cc_mdl_request_list; |
| 19581 | 670343 | uint cc_max_generated_number = 0; | |
| 19582 | |||
| 19583 | /* | ||
| 19584 | Do not process check constraint specification list if master is on version | ||
| 19585 | not supporting check constraints feature. | ||
| 19586 | */ | ||
| 19587 |
3/4✓ Branch 0 taken 670339 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
✓ Branch 3 taken 670312 times.
|
670343 | if (is_slave_with_master_without_check_constraints_support(thd)) { |
| 19588 |
1/2✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
|
27 | alter_info->check_constraint_spec_list.clear(); |
| 19589 | 27 | return false; | |
| 19590 | } | ||
| 19591 | |||
| 19592 |
3/4✓ Branch 0 taken 670316 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 843 times.
✓ Branch 3 taken 670256 times.
|
671095 | for (auto &cc_spec : alter_info->check_constraint_spec_list) { |
| 19593 | // If check constraint name is omitted then generate name. | ||
| 19594 |
2/2✓ Branch 0 taken 219 times.
✓ Branch 1 taken 624 times.
|
843 | if (cc_spec->name.length == 0) { |
| 19595 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 218 times.
|
219 | if (generate_check_constraint_name( |
| 19596 |
1/2✓ Branch 0 taken 219 times.
✗ Branch 1 not taken.
|
219 | thd, table_name, ++cc_max_generated_number, cc_spec->name, false)) |
| 19597 | 1 | return true; | |
| 19598 | } | ||
| 19599 | |||
| 19600 | // Pre-validate check constraint. | ||
| 19601 |
3/4✓ Branch 0 taken 842 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 59 times.
✓ Branch 3 taken 783 times.
|
842 | if (cc_spec->pre_validate()) return true; |
| 19602 | |||
| 19603 | // Create MDL request for the check constraint. | ||
| 19604 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 783 times.
|
783 | if (push_check_constraint_mdl_request_to_list( |
| 19605 |
1/2✓ Branch 0 taken 783 times.
✗ Branch 1 not taken.
|
783 | thd, db_name, cc_spec->name.str, cc_mdl_request_list)) |
| 19606 | ✗ | return true; | |
| 19607 | } | ||
| 19608 | |||
| 19609 | // Make sure fields used by the check constraint exists in the create list. | ||
| 19610 | 670256 | mem_root_deque<Item_field *> fields(thd->mem_root); | |
| 19611 |
3/4✓ Branch 0 taken 670256 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 776 times.
✓ Branch 3 taken 670253 times.
|
671025 | for (auto &cc_spec : alter_info->check_constraint_spec_list) { |
| 19612 |
1/2✓ Branch 0 taken 776 times.
✗ Branch 1 not taken.
|
776 | cc_spec->check_expr->walk(&Item::collect_item_field_processor, |
| 19613 | enum_walk::POSTFIX, (uchar *)&fields); | ||
| 19614 | |||
| 19615 | Create_field *cur_fld; | ||
| 19616 |
1/2✓ Branch 0 taken 776 times.
✗ Branch 1 not taken.
|
776 | List_iterator<Create_field> create_fields_it(alter_info->create_list); |
| 19617 |
7/12✓ Branch 0 taken 776 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 776 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1350 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1347 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2123 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1350 times.
✓ Branch 11 taken 773 times.
|
2123 | for (Item_field *cur_item_fld : fields) { |
| 19618 |
3/4✓ Branch 0 taken 1350 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1349 times.
|
1350 | if (cur_item_fld->type() != Item::FIELD_ITEM) continue; |
| 19619 | |||
| 19620 |
2/2✓ Branch 0 taken 2838 times.
✓ Branch 1 taken 3 times.
|
2841 | while ((cur_fld = create_fields_it++)) { |
| 19621 |
3/4✓ Branch 0 taken 2838 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1346 times.
✓ Branch 3 taken 1492 times.
|
2838 | if (!my_strcasecmp(system_charset_info, cur_item_fld->field_name, |
| 19622 | cur_fld->field_name)) | ||
| 19623 | 1346 | break; | |
| 19624 | } | ||
| 19625 | 1349 | create_fields_it.rewind(); | |
| 19626 | |||
| 19627 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1346 times.
|
1349 | if (cur_fld == nullptr) { |
| 19628 | 3 | my_error(ER_CHECK_CONSTRAINT_REFERS_UNKNOWN_COLUMN, MYF(0), | |
| 19629 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | cc_spec->name.str, cur_item_fld->field_name); |
| 19630 | 3 | return true; | |
| 19631 | } | ||
| 19632 | } | ||
| 19633 |
1/2✓ Branch 0 taken 773 times.
✗ Branch 1 not taken.
|
773 | fields.clear(); |
| 19634 | } | ||
| 19635 | |||
| 19636 |
3/4✓ Branch 0 taken 606466 times.
✓ Branch 1 taken 63783 times.
✓ Branch 2 taken 606471 times.
✗ Branch 3 not taken.
|
670253 | DEBUG_SYNC(thd, "before_acquiring_lock_on_check_constraints"); |
| 19637 |
2/4✓ Branch 0 taken 670251 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 670251 times.
|
670254 | if (thd->mdl_context.acquire_locks(&cc_mdl_request_list, |
| 19638 | thd->variables.lock_wait_timeout)) | ||
| 19639 | ✗ | return true; | |
| 19640 |
3/4✓ Branch 0 taken 606470 times.
✓ Branch 1 taken 63783 times.
✓ Branch 2 taken 606472 times.
✗ Branch 3 not taken.
|
670251 | DEBUG_SYNC(thd, "after_acquiring_lock_on_check_constraints"); |
| 19641 | |||
| 19642 | 670255 | return false; | |
| 19643 | 670345 | } | |
| 19644 | |||
| 19645 | /** | ||
| 19646 | Method to prepare check constraints for the CREATE TABLE LIKE operation. | ||
| 19647 | If check constraints are defined on the source table then check constraints | ||
| 19648 | specifications are prepared for the table being created from it. To | ||
| 19649 | avoid name conflicts, names are generated for all the check constraints | ||
| 19650 | prepared for the table being created. | ||
| 19651 | |||
| 19652 | |||
| 19653 | @param thd Thread handle. | ||
| 19654 | @param src_table TABLE_LIST instance for source table. | ||
| 19655 | @param target_table TABLE_LIST instance for target table. | ||
| 19656 | @param alter_info Alter_info instance to prepare | ||
| 19657 | list of check constraint spec | ||
| 19658 | for table being created. | ||
| 19659 | |||
| 19660 | @retval false Success. | ||
| 19661 | @retval true Failure. | ||
| 19662 | */ | ||
| 19663 | 1168 | static bool prepare_check_constraints_for_create_like_table( | |
| 19664 | THD *thd, TABLE_LIST *src_table, TABLE_LIST *target_table, | ||
| 19665 | Alter_info *alter_info) { | ||
| 19666 |
1/2✓ Branch 0 taken 1168 times.
✗ Branch 1 not taken.
|
1168 | DBUG_TRACE; |
| 19667 |
1/2✓ Branch 0 taken 1168 times.
✗ Branch 1 not taken.
|
1168 | MDL_request_list cc_mdl_request_list; |
| 19668 | 1168 | uint number = 0; | |
| 19669 | |||
| 19670 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1165 times.
|
1168 | if (src_table->table->table_check_constraint_list != nullptr) { |
| 19671 |
3/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 3 times.
|
15 | for (auto &table_cc : *src_table->table->table_check_constraint_list) { |
| 19672 | Sql_check_constraint_spec *cc_spec = | ||
| 19673 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | new (thd->mem_root) Sql_check_constraint_spec; |
| 19674 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | if (cc_spec == nullptr) return true; // OOM |
| 19675 | |||
| 19676 | // For create like table, all the check constraint names are generated to | ||
| 19677 | // avoid name conflicts. | ||
| 19678 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | if (generate_check_constraint_name(thd, target_table->table_name, |
| 19679 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | ++number, cc_spec->name, true)) |
| 19680 | ✗ | return true; | |
| 19681 | |||
| 19682 | // check constraint expression. | ||
| 19683 | 12 | cc_spec->check_expr = table_cc.value_generator()->expr_item; | |
| 19684 | |||
| 19685 | // Copy check constraint status. | ||
| 19686 | 12 | cc_spec->is_enforced = table_cc.is_enforced(); | |
| 19687 | |||
| 19688 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | alter_info->check_constraint_spec_list.push_back(cc_spec); |
| 19689 | |||
| 19690 | /* | ||
| 19691 | Create MDL request for check constraint in source table and the | ||
| 19692 | generated check constraint name for target table. | ||
| 19693 | */ | ||
| 19694 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | if (push_check_constraint_mdl_request_to_list( |
| 19695 |
2/4✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
|
36 | thd, src_table->db, table_cc.name().str, cc_mdl_request_list) || |
| 19696 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | push_check_constraint_mdl_request_to_list( |
| 19697 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | thd, target_table->db, cc_spec->name.str, cc_mdl_request_list)) |
| 19698 | ✗ | return true; | |
| 19699 | } | ||
| 19700 | } | ||
| 19701 | |||
| 19702 |
2/4✓ Branch 0 taken 1168 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1168 times.
✗ Branch 3 not taken.
|
1168 | DEBUG_SYNC(thd, "before_acquiring_lock_on_check_constraints"); |
| 19703 |
2/4✓ Branch 0 taken 1168 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1168 times.
|
1168 | if (thd->mdl_context.acquire_locks(&cc_mdl_request_list, |
| 19704 | thd->variables.lock_wait_timeout)) | ||
| 19705 | ✗ | return true; | |
| 19706 |
2/4✓ Branch 0 taken 1168 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1168 times.
✗ Branch 3 not taken.
|
1168 | DEBUG_SYNC(thd, "after_acquiring_lock_on_check_constraints"); |
| 19707 | |||
| 19708 | 1168 | return false; | |
| 19709 | 1168 | } | |
| 19710 | |||
| 19711 | /** | ||
| 19712 | Method to prepare check constraints for the ALTER TABLE operation. | ||
| 19713 | Method prepares check constraints specifications from the existing | ||
| 19714 | list of check constraints on the table, appends new check constraints | ||
| 19715 | to list, updates state (enforced/not enforced) and drop any existing | ||
| 19716 | check constraint from the list. | ||
| 19717 | |||
| 19718 | @param thd Thread handle. | ||
| 19719 | @param table TABLE instance of source table. | ||
| 19720 | @param alter_info Alter_info object to prepare | ||
| 19721 | list of check constraint spec | ||
| 19722 | for table being altered. | ||
| 19723 | @param alter_tbl_ctx Runtime context for | ||
| 19724 | ALTER TABLE. | ||
| 19725 | |||
| 19726 | @retval false Success. | ||
| 19727 | @retval true Failure. | ||
| 19728 | */ | ||
| 19729 | 89527 | static bool prepare_check_constraints_for_alter( | |
| 19730 | THD *thd, const TABLE *table, Alter_info *alter_info, | ||
| 19731 | Alter_table_ctx *alter_tbl_ctx) { | ||
| 19732 |
1/2✓ Branch 0 taken 89527 times.
✗ Branch 1 not taken.
|
89527 | DBUG_TRACE; |
| 19733 |
1/2✓ Branch 0 taken 89527 times.
✗ Branch 1 not taken.
|
89527 | MDL_request_list cc_mdl_request_list; |
| 19734 |
1/2✓ Branch 0 taken 89527 times.
✗ Branch 1 not taken.
|
89527 | Sql_check_constraint_spec_list new_check_cons_list(thd->mem_root); |
| 19735 | 89527 | uint cc_max_generated_number = 0; | |
| 19736 | 89527 | uint table_name_len = strlen(alter_tbl_ctx->table_name); | |
| 19737 | |||
| 19738 | /* | ||
| 19739 | Do not process check constraint specification list if master is on version | ||
| 19740 | not supporting check constraints feature. | ||
| 19741 | */ | ||
| 19742 |
3/4✓ Branch 0 taken 89527 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 89525 times.
|
89527 | if (is_slave_with_master_without_check_constraints_support(thd)) { |
| 19743 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | alter_info->check_constraint_spec_list.clear(); |
| 19744 | 2 | return false; | |
| 19745 | } | ||
| 19746 | |||
| 19747 | 1163 | auto find_cc_name = [](std::vector<const char *> &names, const char *s) { | |
| 19748 |
1/2✓ Branch 0 taken 1163 times.
✗ Branch 1 not taken.
|
1163 | auto name = find_if(names.begin(), names.end(), [s](const char *cc_name) { |
| 19749 | 135 | return !my_strcasecmp(system_charset_info, s, cc_name); | |
| 19750 | }); | ||
| 19751 |
2/2✓ Branch 0 taken 64 times.
✓ Branch 1 taken 1099 times.
|
1163 | return (name != names.end()) ? *name : nullptr; |
| 19752 | }; | ||
| 19753 | |||
| 19754 | /* | ||
| 19755 | List of check constraint names. Used after acquiring MDL locks on final list | ||
| 19756 | of check constraints to verify if check constraint names conflict with | ||
| 19757 | existing check constraint names. | ||
| 19758 | */ | ||
| 19759 | 89525 | std::vector<const char *> new_cc_names; | |
| 19760 | |||
| 19761 | /* | ||
| 19762 | Handle check constraint specifications marked for drop. | ||
| 19763 | |||
| 19764 | Prepare list of check constraint names (Pointer to the constraint name in | ||
| 19765 | Alter_drop instances) marked for drop. List is used to skip constraints | ||
| 19766 | while preparing specification list from existing check constraints and | ||
| 19767 | while adding new check constraints with the same name. | ||
| 19768 | */ | ||
| 19769 | 89525 | std::vector<const char *> dropped_cc_names; | |
| 19770 |
3/4✓ Branch 0 taken 89525 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12203 times.
✓ Branch 3 taken 89522 times.
|
101725 | for (const Alter_drop *drop : alter_info->drop_list) { |
| 19771 |
2/2✓ Branch 0 taken 12155 times.
✓ Branch 1 taken 48 times.
|
12203 | if (drop->type != Alter_drop::CHECK_CONSTRAINT) continue; |
| 19772 | |||
| 19773 | 48 | bool cc_found = false; | |
| 19774 |
2/2✓ Branch 0 taken 47 times.
✓ Branch 1 taken 1 times.
|
48 | if (table->table_check_constraint_list != nullptr) { |
| 19775 | 37 | for (Sql_table_check_constraint &table_cc : | |
| 19776 |
3/4✓ Branch 0 taken 47 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 82 times.
✓ Branch 3 taken 2 times.
|
84 | *table->table_check_constraint_list) { |
| 19777 |
3/4✓ Branch 0 taken 82 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 45 times.
✓ Branch 3 taken 37 times.
|
82 | if (!my_strcasecmp(system_charset_info, table_cc.name().str, |
| 19778 | drop->name)) { | ||
| 19779 |
1/2✓ Branch 0 taken 45 times.
✗ Branch 1 not taken.
|
45 | dropped_cc_names.push_back(drop->name); |
| 19780 | 45 | cc_found = true; | |
| 19781 | 45 | break; | |
| 19782 | } | ||
| 19783 | } | ||
| 19784 | } | ||
| 19785 | |||
| 19786 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 45 times.
|
48 | if (!cc_found) { |
| 19787 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | my_error(ER_CHECK_CONSTRAINT_NOT_FOUND, MYF(0), drop->name); |
| 19788 | 3 | return true; | |
| 19789 | } | ||
| 19790 | } | ||
| 19791 | |||
| 19792 | /* | ||
| 19793 | Auto-drop check constraint: If check constraint refers to only one column | ||
| 19794 | and that column is marked for drop then drop | ||
| 19795 | check constraint too. | ||
| 19796 | Check constraints marked for auto-drop are added to list of check constraint | ||
| 19797 | (dropped_cc_names) to be dropped. | ||
| 19798 | */ | ||
| 19799 |
2/2✓ Branch 0 taken 778 times.
✓ Branch 1 taken 88744 times.
|
89522 | if (table->table_check_constraint_list != nullptr) { |
| 19800 |
3/4✓ Branch 0 taken 778 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 488 times.
✓ Branch 3 taken 778 times.
|
1266 | for (const Alter_drop *drop : alter_info->drop_list) { |
| 19801 |
2/2✓ Branch 0 taken 172 times.
✓ Branch 1 taken 316 times.
|
488 | if (drop->type == Alter_drop::COLUMN) { |
| 19802 | 178 | for (Sql_table_check_constraint &table_cc : | |
| 19803 |
3/4✓ Branch 0 taken 172 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 178 times.
✓ Branch 3 taken 172 times.
|
350 | *table->table_check_constraint_list) { |
| 19804 |
3/4✓ Branch 0 taken 178 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 170 times.
|
178 | if (check_constraint_expr_refers_to_only_column( |
| 19805 | 178 | table_cc.value_generator()->expr_item, drop->name)) | |
| 19806 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | dropped_cc_names.push_back(table_cc.name().str); |
| 19807 | } | ||
| 19808 | } | ||
| 19809 | } | ||
| 19810 | } | ||
| 19811 | |||
| 19812 | /* | ||
| 19813 | Prepare check constraint specification for the existing check constraints on | ||
| 19814 | the table. | ||
| 19815 | |||
| 19816 | * Skip check constraint specification marked for drop. | ||
| 19817 | |||
| 19818 | * Get max sequence number for generated names. This is required when | ||
| 19819 | handling new check constraints added to the table. | ||
| 19820 | |||
| 19821 | * If table is renamed, adjust generated check constraint names to use new | ||
| 19822 | table name. | ||
| 19823 | |||
| 19824 | * Create MDL request on all check constraints. | ||
| 19825 | - Also on adjusted check constraint names if table is renamed. | ||
| 19826 | - If database changed then on all check constraints with the new database. | ||
| 19827 | */ | ||
| 19828 |
2/2✓ Branch 0 taken 778 times.
✓ Branch 1 taken 88744 times.
|
89522 | if (table->table_check_constraint_list != nullptr) { |
| 19829 |
3/4✓ Branch 0 taken 778 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1024 times.
✓ Branch 3 taken 778 times.
|
1802 | for (auto &table_cc : *table->table_check_constraint_list) { |
| 19830 | /* | ||
| 19831 | Push MDL_request for the existing check constraint name. | ||
| 19832 | Note: Notice that this also handles case of dropped constraints. | ||
| 19833 | */ | ||
| 19834 |
2/4✓ Branch 0 taken 1024 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1024 times.
|
1024 | if (push_check_constraint_mdl_request_to_list( |
| 19835 | 1024 | thd, alter_tbl_ctx->db, table_cc.name().str, cc_mdl_request_list)) | |
| 19836 | ✗ | return true; | |
| 19837 | |||
| 19838 | // Skip if constraint is marked for drop. | ||
| 19839 |
3/4✓ Branch 0 taken 1024 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 51 times.
✓ Branch 3 taken 973 times.
|
1024 | if (find_cc_name(dropped_cc_names, table_cc.name().str) != nullptr) |
| 19840 | 51 | continue; | |
| 19841 | |||
| 19842 | Sql_check_constraint_spec *cc_spec = | ||
| 19843 |
1/2✓ Branch 0 taken 973 times.
✗ Branch 1 not taken.
|
973 | new (thd->mem_root) Sql_check_constraint_spec; |
| 19844 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 973 times.
|
973 | if (cc_spec == nullptr) return true; // OOM |
| 19845 | |||
| 19846 |
1/2✓ Branch 0 taken 973 times.
✗ Branch 1 not taken.
|
973 | bool is_generated_name = dd::is_generated_check_constraint_name( |
| 19847 | 973 | alter_tbl_ctx->table_name, table_name_len, table_cc.name().str, | |
| 19848 | 973 | table_cc.name().length); | |
| 19849 | /* | ||
| 19850 | Get number from generated name and update max generated number if | ||
| 19851 | needed. | ||
| 19852 | */ | ||
| 19853 |
2/2✓ Branch 0 taken 299 times.
✓ Branch 1 taken 674 times.
|
973 | if (is_generated_name) { |
| 19854 | char *end; | ||
| 19855 | uint number = | ||
| 19856 | 299 | my_strtoull(table_cc.name().str + table_name_len + | |
| 19857 | 299 | sizeof(dd::CHECK_CONSTRAINT_NAME_SUBSTR) - 1, | |
| 19858 | 299 | &end, 10); | |
| 19859 |
2/2✓ Branch 0 taken 231 times.
✓ Branch 1 taken 68 times.
|
299 | if (number > cc_max_generated_number) cc_max_generated_number = number; |
| 19860 | } | ||
| 19861 | |||
| 19862 | // If generated name and table is renamed then update generated name. | ||
| 19863 |
6/6✓ Branch 0 taken 299 times.
✓ Branch 1 taken 674 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 290 times.
✓ Branch 4 taken 9 times.
✓ Branch 5 taken 964 times.
|
973 | if (is_generated_name && alter_tbl_ctx->is_table_name_changed()) { |
| 19864 | char *end; | ||
| 19865 | uint number = | ||
| 19866 | 9 | my_strtoull(table_cc.name().str + table_name_len + | |
| 19867 | 9 | sizeof(dd::CHECK_CONSTRAINT_NAME_SUBSTR) - 1, | |
| 19868 | 9 | &end, 10); | |
| 19869 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
|
9 | if (number > cc_max_generated_number) cc_max_generated_number = number; |
| 19870 | |||
| 19871 | // Generate new check constraint name. | ||
| 19872 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
|
9 | if (generate_check_constraint_name(thd, alter_tbl_ctx->new_name, number, |
| 19873 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
9 | cc_spec->name, true)) |
| 19874 | ✗ | return true; | |
| 19875 | } else { | ||
| 19876 |
1/2✓ Branch 0 taken 964 times.
✗ Branch 1 not taken.
|
964 | lex_string_strmake(thd->mem_root, &cc_spec->name, table_cc.name().str, |
| 19877 | 964 | table_cc.name().length); | |
| 19878 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 964 times.
|
964 | if (cc_spec->name.str == nullptr) return true; // OOM |
| 19879 | } | ||
| 19880 | |||
| 19881 | // check constraint expression. | ||
| 19882 | 973 | cc_spec->check_expr = table_cc.value_generator()->expr_item; | |
| 19883 | |||
| 19884 | // Copy check constraint status. | ||
| 19885 | 973 | cc_spec->is_enforced = table_cc.is_enforced(); | |
| 19886 | |||
| 19887 | // Push check constraint to new list. | ||
| 19888 |
1/2✓ Branch 0 taken 973 times.
✗ Branch 1 not taken.
|
973 | new_check_cons_list.push_back(cc_spec); |
| 19889 | |||
| 19890 | /* | ||
| 19891 | If db is changed then push MDL_request on check constraint with new db | ||
| 19892 | name or if table name is changed then push MDL_request on generated | ||
| 19893 | check constraint name. | ||
| 19894 | */ | ||
| 19895 |
6/6✓ Branch 0 taken 971 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 959 times.
✓ Branch 4 taken 10 times.
✓ Branch 5 taken 963 times.
|
1956 | if ((alter_tbl_ctx->is_database_changed() || |
| 19896 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
|
983 | (alter_tbl_ctx->is_table_name_changed() && is_generated_name))) { |
| 19897 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if (push_check_constraint_mdl_request_to_list( |
| 19898 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | thd, alter_tbl_ctx->new_db, cc_spec->name.str, |
| 19899 | cc_mdl_request_list)) | ||
| 19900 | ✗ | return true; | |
| 19901 | |||
| 19902 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | new_cc_names.push_back(cc_spec->name.str); |
| 19903 | } | ||
| 19904 | } | ||
| 19905 | |||
| 19906 | /* | ||
| 19907 | Check if any check constraint refers to column(s) being dropped or | ||
| 19908 | renamed. | ||
| 19909 | */ | ||
| 19910 |
3/4✓ Branch 0 taken 778 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 744 times.
✓ Branch 3 taken 34 times.
|
778 | if (!new_check_cons_list.empty()) { |
| 19911 | // Check if any check constraint refers column(s) being dropped. | ||
| 19912 |
4/6✓ Branch 0 taken 744 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 744 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 741 times.
|
744 | if (std::any_of( |
| 19913 | alter_info->drop_list.begin(), alter_info->drop_list.end(), | ||
| 19914 | Check_constraint_column_dependency_checker(new_check_cons_list))) | ||
| 19915 | 3 | return true; | |
| 19916 | |||
| 19917 | /* | ||
| 19918 | Check if any check constraint refers column(s) being renamed using | ||
| 19919 | RENAME COLUMN clause. | ||
| 19920 | */ | ||
| 19921 |
4/6✓ Branch 0 taken 741 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 741 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 737 times.
|
741 | if (std::any_of( |
| 19922 | alter_info->alter_list.begin(), alter_info->alter_list.end(), | ||
| 19923 | Check_constraint_column_dependency_checker(new_check_cons_list))) | ||
| 19924 | 4 | return true; | |
| 19925 | |||
| 19926 | /* | ||
| 19927 | Check if any check constraint refers column(s) being renamed using | ||
| 19928 | CHANGE [COLUMN] clause. | ||
| 19929 | */ | ||
| 19930 |
5/8✓ Branch 0 taken 737 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 737 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 737 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 736 times.
|
737 | if (std::any_of( |
| 19931 | alter_info->create_list.begin(), alter_info->create_list.end(), | ||
| 19932 | Check_constraint_column_dependency_checker(new_check_cons_list))) | ||
| 19933 | 1 | return true; | |
| 19934 | } | ||
| 19935 | } | ||
| 19936 | |||
| 19937 | // Update check constraint enforcement state (i.e. enforced or not enforced). | ||
| 19938 |
3/4✓ Branch 0 taken 89514 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 166 times.
✓ Branch 3 taken 89501 times.
|
89667 | for (auto *alter_constraint : alter_info->alter_constraint_enforcement_list) { |
| 19939 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 156 times.
|
166 | if (alter_constraint->type != |
| 19940 | Alter_constraint_enforcement::Type::CHECK_CONSTRAINT) | ||
| 19941 | 10 | continue; | |
| 19942 | |||
| 19943 | 156 | bool cc_found = false; | |
| 19944 |
3/4✓ Branch 0 taken 156 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 162 times.
✓ Branch 3 taken 13 times.
|
175 | for (auto &cc_spec : new_check_cons_list) { |
| 19945 |
3/4✓ Branch 0 taken 162 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 143 times.
✓ Branch 3 taken 19 times.
|
162 | if (!my_strcasecmp(system_charset_info, cc_spec->name.str, |
| 19946 | alter_constraint->name)) { | ||
| 19947 | 143 | cc_found = true; | |
| 19948 | // Update status. | ||
| 19949 | 143 | cc_spec->is_enforced = alter_constraint->is_enforced; | |
| 19950 | 143 | break; | |
| 19951 | } | ||
| 19952 | } | ||
| 19953 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 143 times.
|
156 | if (!cc_found) { |
| 19954 |
1/2✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
|
13 | my_error(ER_CHECK_CONSTRAINT_NOT_FOUND, MYF(0), alter_constraint->name); |
| 19955 | 13 | return true; | |
| 19956 | } | ||
| 19957 | } | ||
| 19958 | |||
| 19959 | /* | ||
| 19960 | Handle new check constraints added to the table. | ||
| 19961 | |||
| 19962 | * Generate name if name is not specified. | ||
| 19963 | If table already has check constraints with generated name then use | ||
| 19964 | sequence number generated when handling existing check constraint names. | ||
| 19965 | |||
| 19966 | * pre-validate check constraint. | ||
| 19967 | |||
| 19968 | * Prepare MDL request for new check constraints. | ||
| 19969 | */ | ||
| 19970 |
3/4✓ Branch 0 taken 89501 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 140 times.
✓ Branch 3 taken 89500 times.
|
89640 | for (auto &cc_spec : alter_info->check_constraint_spec_list) { |
| 19971 | // If check constraint name is omitted then generate name. | ||
| 19972 |
2/2✓ Branch 0 taken 62 times.
✓ Branch 1 taken 78 times.
|
140 | if (cc_spec->name.length == 0) { |
| 19973 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 61 times.
|
62 | if (generate_check_constraint_name(thd, alter_tbl_ctx->new_name, |
| 19974 | ++cc_max_generated_number, | ||
| 19975 |
1/2✓ Branch 0 taken 62 times.
✗ Branch 1 not taken.
|
62 | cc_spec->name, false)) |
| 19976 | 1 | return true; | |
| 19977 | } | ||
| 19978 | |||
| 19979 |
2/4✓ Branch 0 taken 139 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 139 times.
|
139 | if (cc_spec->pre_validate()) return true; |
| 19980 | |||
| 19981 | // Push check constraint to new list. | ||
| 19982 |
1/2✓ Branch 0 taken 139 times.
✗ Branch 1 not taken.
|
139 | new_check_cons_list.push_back(cc_spec); |
| 19983 | |||
| 19984 | // Create MDL request for the check constraint. | ||
| 19985 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 139 times.
|
139 | if (push_check_constraint_mdl_request_to_list( |
| 19986 |
1/2✓ Branch 0 taken 139 times.
✗ Branch 1 not taken.
|
139 | thd, alter_tbl_ctx->new_db, cc_spec->name.str, cc_mdl_request_list)) |
| 19987 | ✗ | return true; | |
| 19988 | |||
| 19989 | /* | ||
| 19990 | We need to check if conflicting constraint name exists for all newly added | ||
| 19991 | constraints. However, we don't need (and it is inconvenient) to do this | ||
| 19992 | if constraint with the same name was dropped by the same ALTER TABLE, | ||
| 19993 | unless old and new constraints belong to different databases (i.e. this | ||
| 19994 | ALTER TABLE also moves table between databases). | ||
| 19995 | */ | ||
| 19996 |
3/4✓ Branch 0 taken 139 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 126 times.
✓ Branch 3 taken 13 times.
|
278 | if (alter_tbl_ctx->is_database_changed() || |
| 19997 |
3/4✓ Branch 0 taken 139 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 126 times.
✓ Branch 3 taken 13 times.
|
139 | find_cc_name(dropped_cc_names, cc_spec->name.str) == nullptr) |
| 19998 |
1/2✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
|
126 | new_cc_names.push_back(cc_spec->name.str); |
| 19999 | } | ||
| 20000 | |||
| 20001 | /* | ||
| 20002 | Adjust Alter_info::flags. | ||
| 20003 | |||
| 20004 | * Check if final list has any check constraint whose state is changed from | ||
| 20005 | NOT ENFORCED to ENFORCED. | ||
| 20006 | |||
| 20007 | * Check if list has any new check constraints added with ENFORCED state. | ||
| 20008 | |||
| 20009 | * Update Alter_info::flags accordingly. | ||
| 20010 | */ | ||
| 20011 | 89500 | bool final_enforced_state = false; | |
| 20012 |
3/4✓ Branch 0 taken 89500 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1040 times.
✓ Branch 3 taken 89382 times.
|
90422 | for (auto &cc : new_check_cons_list) { |
| 20013 | // Check if any of existing constraint is enforced. | ||
| 20014 |
2/2✓ Branch 0 taken 994 times.
✓ Branch 1 taken 46 times.
|
1040 | if (table->table_check_constraint_list != nullptr) { |
| 20015 |
3/4✓ Branch 0 taken 994 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2630 times.
✓ Branch 3 taken 980 times.
|
3610 | for (auto &table_cc : *table->table_check_constraint_list) { |
| 20016 |
1/2✓ Branch 0 taken 2630 times.
✗ Branch 1 not taken.
|
2630 | if (!my_strcasecmp(system_charset_info, cc->name.str, |
| 20017 | 924 | table_cc.name().str) && | |
| 20018 |
8/8✓ Branch 0 taken 924 times.
✓ Branch 1 taken 1706 times.
✓ Branch 2 taken 606 times.
✓ Branch 3 taken 318 times.
✓ Branch 4 taken 14 times.
✓ Branch 5 taken 592 times.
✓ Branch 6 taken 14 times.
✓ Branch 7 taken 2616 times.
|
2630 | !table_cc.is_enforced() && cc->is_enforced) { |
| 20019 | 14 | final_enforced_state = true; | |
| 20020 | 14 | break; | |
| 20021 | } | ||
| 20022 | } | ||
| 20023 | } | ||
| 20024 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 1026 times.
|
1040 | if (final_enforced_state) break; |
| 20025 | |||
| 20026 | // Check if new constraint is added in enforced state. | ||
| 20027 |
3/4✓ Branch 0 taken 1026 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 349 times.
✓ Branch 3 taken 922 times.
|
1271 | for (auto &new_cc : alter_info->check_constraint_spec_list) { |
| 20028 |
5/6✓ Branch 0 taken 349 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 116 times.
✓ Branch 3 taken 233 times.
✓ Branch 4 taken 104 times.
✓ Branch 5 taken 245 times.
|
465 | if (!my_strcasecmp(system_charset_info, cc->name.str, new_cc->name.str) && |
| 20029 |
2/2✓ Branch 0 taken 104 times.
✓ Branch 1 taken 12 times.
|
116 | cc->is_enforced) { |
| 20030 | 104 | final_enforced_state = true; | |
| 20031 | 104 | break; | |
| 20032 | } | ||
| 20033 | } | ||
| 20034 |
2/2✓ Branch 0 taken 104 times.
✓ Branch 1 taken 922 times.
|
1026 | if (final_enforced_state) break; |
| 20035 | } | ||
| 20036 |
2/2✓ Branch 0 taken 118 times.
✓ Branch 1 taken 89382 times.
|
89500 | if (final_enforced_state) |
| 20037 | 118 | alter_info->flags |= Alter_info::ENFORCE_CHECK_CONSTRAINT; | |
| 20038 | else | ||
| 20039 | 89382 | alter_info->flags &= ~Alter_info::ENFORCE_CHECK_CONSTRAINT; | |
| 20040 | |||
| 20041 | /* | ||
| 20042 | Set alter mode for each check constraint specification instance. | ||
| 20043 | |||
| 20044 | For non-temporary table prepare temporary check constraint names. During | ||
| 20045 | ALTER TABLE operation, two versions of table exists and to avoid check | ||
| 20046 | constraint name conflicts temporary(adjusted) names stored for newer | ||
| 20047 | version and alter mode is set. Check constraint names are restored | ||
| 20048 | later in ALTER TABLE operation. MDL request to temporary name is also | ||
| 20049 | created to avoid creation of table with same name by concurrent operation. | ||
| 20050 | |||
| 20051 | * Prepare temporary(adjusted) name for each check constraint specification. | ||
| 20052 | |||
| 20053 | * Set alter mode for each check constraint specification. | ||
| 20054 | |||
| 20055 | * Prepare MDL request for each temporary name. | ||
| 20056 | */ | ||
| 20057 |
2/2✓ Branch 0 taken 88320 times.
✓ Branch 1 taken 1180 times.
|
89500 | if (table->s->tmp_table == NO_TMP_TABLE) { |
| 20058 | 88320 | ulong id = 1; | |
| 20059 |
3/4✓ Branch 0 taken 88320 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1064 times.
✓ Branch 3 taken 88320 times.
|
89384 | for (Sql_check_constraint_spec *cc : new_check_cons_list) { |
| 20060 | 1064 | const int prefix_len = 3; // #cc | |
| 20061 | 1064 | const int process_id_len = 20; | |
| 20062 | 1064 | const int thread_id_len = 10; | |
| 20063 | 1064 | const int id_len = 20; | |
| 20064 | 1064 | const int separator_len = 1; | |
| 20065 | char temp_name_buf[prefix_len + process_id_len + thread_id_len + id_len + | ||
| 20066 | (separator_len * 3) + 1]; | ||
| 20067 | 1064 | snprintf(temp_name_buf, sizeof(temp_name_buf), "#cc_%lu_%u_%lu", | |
| 20068 | current_pid, thd->thread_id(), id++); | ||
| 20069 | |||
| 20070 | // Create MDL request for the temp check constraint name. | ||
| 20071 |
2/4✓ Branch 0 taken 1064 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1064 times.
|
1064 | if (push_check_constraint_mdl_request_to_list( |
| 20072 | thd, alter_tbl_ctx->new_db, temp_name_buf, cc_mdl_request_list)) | ||
| 20073 | ✗ | return true; | |
| 20074 | |||
| 20075 | 1064 | cc->is_alter_mode = true; | |
| 20076 | 1064 | cc->alias_name.length = strlen(temp_name_buf); | |
| 20077 | 1064 | cc->alias_name.str = | |
| 20078 |
1/2✓ Branch 0 taken 1064 times.
✗ Branch 1 not taken.
|
1064 | strmake_root(thd->mem_root, temp_name_buf, cc->alias_name.length); |
| 20079 | } | ||
| 20080 | } | ||
| 20081 | |||
| 20082 | // Acquire MDL lock on all the MDL_request prepared in this method. | ||
| 20083 |
3/4✓ Branch 0 taken 87120 times.
✓ Branch 1 taken 2380 times.
✓ Branch 2 taken 87120 times.
✗ Branch 3 not taken.
|
89500 | DEBUG_SYNC(thd, "before_acquiring_lock_on_check_constraints"); |
| 20084 |
2/4✓ Branch 0 taken 89500 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 89500 times.
|
89500 | if (thd->mdl_context.acquire_locks(&cc_mdl_request_list, |
| 20085 | thd->variables.lock_wait_timeout)) | ||
| 20086 | ✗ | return true; | |
| 20087 |
3/4✓ Branch 0 taken 87120 times.
✓ Branch 1 taken 2380 times.
✓ Branch 2 taken 87120 times.
✗ Branch 3 not taken.
|
89500 | DEBUG_SYNC(thd, "after_acquiring_lock_on_check_constraints"); |
| 20088 | |||
| 20089 | /* | ||
| 20090 | Make sure new check constraint names do not conflict with any existing check | ||
| 20091 | constraint names before starting expensive ALTER operation. | ||
| 20092 | */ | ||
| 20093 | 89500 | dd::Schema_MDL_locker mdl_locker(thd); | |
| 20094 | 89500 | const dd::Schema *new_schema = nullptr; | |
| 20095 |
1/2✓ Branch 0 taken 89500 times.
✗ Branch 1 not taken.
|
89500 | dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client()); |
| 20096 |
2/4✓ Branch 0 taken 89500 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 89500 times.
✗ Branch 3 not taken.
|
179000 | if (mdl_locker.ensure_locked(alter_tbl_ctx->new_db) || |
| 20097 |
5/12✓ Branch 0 taken 89500 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 89500 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 89500 times.
✓ Branch 6 taken 89500 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 89500 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
179000 | thd->dd_client()->acquire(alter_tbl_ctx->new_db, &new_schema)) |
| 20098 | ✗ | return true; | |
| 20099 | 89500 | bool exists = false; | |
| 20100 |
2/2✓ Branch 0 taken 136 times.
✓ Branch 1 taken 89497 times.
|
89633 | for (auto cc_name : new_cc_names) { |
| 20101 |
3/6✓ Branch 0 taken 136 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 136 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 136 times.
|
136 | if (thd->dd_client()->check_constraint_exists(*new_schema, cc_name, |
| 20102 | &exists)) | ||
| 20103 | 3 | return true; | |
| 20104 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 133 times.
|
136 | if (exists) { |
| 20105 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | my_error(ER_CHECK_CONSTRAINT_DUP_NAME, MYF(0), cc_name); |
| 20106 | 3 | return true; | |
| 20107 | } | ||
| 20108 | } | ||
| 20109 | |||
| 20110 |
1/2✓ Branch 0 taken 89497 times.
✗ Branch 1 not taken.
|
89497 | alter_info->check_constraint_spec_list.clear(); |
| 20111 |
1/2✓ Branch 0 taken 89497 times.
✗ Branch 1 not taken.
|
89497 | alter_info->check_constraint_spec_list.resize(new_check_cons_list.size()); |
| 20112 |
2/4✓ Branch 0 taken 89497 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 89497 times.
✗ Branch 3 not taken.
|
89497 | std::move(new_check_cons_list.begin(), new_check_cons_list.end(), |
| 20113 | alter_info->check_constraint_spec_list.begin()); | ||
| 20114 | |||
| 20115 | 89497 | return false; | |
| 20116 | 89527 | } | |
| 20117 | |||
| 20118 | /** | ||
| 20119 | During alter table operation, check constraints of a new table are marked as | ||
| 20120 | in alter mode. If a table object is stored to the data-dictionary in this | ||
| 20121 | mode then alias name is stored to avoid name conflicts due to two versions | ||
| 20122 | of table objects. dd::Table object of a new table read from the | ||
| 20123 | data-dictionary contains only alias name. So dd::Table object of a new table | ||
| 20124 | is patched up here with the real name and alter mode to reflect the fact the | ||
| 20125 | check constraint is in alter_mode as this information is not stored | ||
| 20126 | parsistently. | ||
| 20127 | |||
| 20128 | @param new_table New table definition. | ||
| 20129 | @param alter_info Alter_info object containing list of list of | ||
| 20130 | check constraint spec for table being | ||
| 20131 | altered. | ||
| 20132 | */ | ||
| 20133 | 34429 | static void set_check_constraints_alter_mode(dd::Table *new_table, | |
| 20134 | Alter_info *alter_info) { | ||
| 20135 |
6/10✓ Branch 0 taken 34429 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 34429 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 34429 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 641 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 641 times.
✓ Branch 9 taken 34429 times.
|
35070 | for (dd::Check_constraint *cc : *new_table->check_constraints()) { |
| 20136 |
3/4✓ Branch 0 taken 641 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 636 times.
✓ Branch 3 taken 5 times.
|
641 | if (cc->is_alter_mode()) continue; |
| 20137 | 5 | for (Sql_check_constraint_spec *cc_spec : | |
| 20138 |
3/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 5 times.
|
10 | alter_info->check_constraint_spec_list) { |
| 20139 |
3/6✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
|
5 | if (!my_strcasecmp(system_charset_info, cc->name().c_str(), |
| 20140 | cc_spec->alias_name.str)) { | ||
| 20141 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | cc->set_name(cc_spec->name.str); |
| 20142 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | cc->set_alias_name(cc_spec->alias_name.str); |
| 20143 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | cc->set_alter_mode(true); |
| 20144 | } | ||
| 20145 | } | ||
| 20146 | } | ||
| 20147 | 34429 | } | |
| 20148 | |||
| 20149 | /** | ||
| 20150 | Reset alter mode of check constraints. | ||
| 20151 | |||
| 20152 | Method updates only dd::Table object. It is not stored or updated to | ||
| 20153 | data-dictionary in this method. | ||
| 20154 | |||
| 20155 | @param new_table New table definition. | ||
| 20156 | */ | ||
| 20157 | 75172 | static void reset_check_constraints_alter_mode(dd::Table *new_table) { | |
| 20158 |
6/10✓ Branch 0 taken 75172 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 75172 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 75172 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 946 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 946 times.
✓ Branch 9 taken 75172 times.
|
76118 | for (dd::Check_constraint *cc : *new_table->check_constraints()) { |
| 20159 |
2/4✓ Branch 0 taken 946 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 946 times.
|
946 | assert(cc->is_alter_mode()); |
| 20160 |
1/2✓ Branch 0 taken 946 times.
✗ Branch 1 not taken.
|
946 | cc->set_alter_mode(false); |
| 20161 | } | ||
| 20162 | 75172 | } | |
| 20163 | |||
| 20164 | /** | ||
| 20165 | Make old table definition's check constraint use temporary names. This is | ||
| 20166 | needed to avoid problems with duplicate check constraint names while we | ||
| 20167 | have two definitions of the same table. | ||
| 20168 | Method updates only dd::Table object. It is not stored or updated to | ||
| 20169 | data-dictionary in this method. | ||
| 20170 | |||
| 20171 | @param thd Thread context. | ||
| 20172 | @param old_table_db Database of old table. | ||
| 20173 | @param old_table Old table definition. | ||
| 20174 | |||
| 20175 | @returns false - Success, true - Failure. | ||
| 20176 | */ | ||
| 20177 | 18334 | static bool adjust_check_constraint_names_for_old_table_version( | |
| 20178 | THD *thd, const char *old_table_db, dd::Table *old_table) { | ||
| 20179 |
1/2✓ Branch 0 taken 18334 times.
✗ Branch 1 not taken.
|
18334 | MDL_request_list mdl_requests; |
| 20180 |
6/10✓ Branch 0 taken 18334 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18334 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18334 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 562 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 562 times.
✓ Branch 9 taken 18334 times.
|
18896 | for (dd::Check_constraint *cc : *old_table->check_constraints()) { |
| 20181 | 562 | const int prefix_len = 4; // #cc_ | |
| 20182 | 562 | const int id_len = 20; | |
| 20183 | char temp_cc_name[prefix_len + id_len + 1]; | ||
| 20184 | 1124 | snprintf(temp_cc_name, sizeof(temp_cc_name), "#cc_%llu", | |
| 20185 |
1/2✓ Branch 0 taken 562 times.
✗ Branch 1 not taken.
|
562 | (ulonglong)cc->id()); |
| 20186 | |||
| 20187 | /* | ||
| 20188 | Acquire lock on temporary names before updating data-dictionary just in | ||
| 20189 | case somebody tries to create check constraints with same name. | ||
| 20190 | */ | ||
| 20191 |
2/4✓ Branch 0 taken 562 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 562 times.
|
562 | if (push_check_constraint_mdl_request_to_list(thd, old_table_db, |
| 20192 | temp_cc_name, mdl_requests)) | ||
| 20193 | ✗ | return true; | |
| 20194 | |||
| 20195 | // Set adjusted name. | ||
| 20196 |
2/4✓ Branch 0 taken 562 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 562 times.
✗ Branch 3 not taken.
|
562 | cc->set_name(temp_cc_name); |
| 20197 | } | ||
| 20198 | |||
| 20199 |
2/4✓ Branch 0 taken 18334 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 18334 times.
|
18334 | if (thd->mdl_context.acquire_locks(&mdl_requests, |
| 20200 | thd->variables.lock_wait_timeout)) | ||
| 20201 | ✗ | return true; | |
| 20202 | |||
| 20203 | 18334 | return false; | |
| 20204 | } | ||
| 20205 | |||
| 20206 | /** | ||
| 20207 | Helper method to check if any check constraints (re-)evaluation is required. | ||
| 20208 | If any check constraint re-evaluation is required then in-place alter is not | ||
| 20209 | possible as it is done in the SQL-layer. This method is called by | ||
| 20210 | is_inplace_alter_impossible() to check inplace alter is possible. | ||
| 20211 | |||
| 20212 | Check constraint (re-)evaluation is required when | ||
| 20213 | 1) New check constraint is added in ENFORCED state. | ||
| 20214 | 2) Any existing check constraint is ENFORCED. | ||
| 20215 | 3) Type of column used by any enforced check constraint is changed. | ||
| 20216 | 4) check constraints expression depends on DEFAULT function on a column and | ||
| 20217 | default is changed as part of alter operation. | ||
| 20218 | |||
| 20219 | @param alter_info Data related to detected changes. | ||
| 20220 | |||
| 20221 | @retval true Check constraint (re-)evaluation required. | ||
| 20222 | @retval false Otherwise. | ||
| 20223 | */ | ||
| 20224 | 86984 | static bool is_any_check_constraints_evaluation_required( | |
| 20225 | const Alter_info *alter_info) { | ||
| 20226 | /* | ||
| 20227 | Check if any check constraint is added in enforced state or state of any | ||
| 20228 | check is is changed to ENFORCED. | ||
| 20229 | */ | ||
| 20230 |
2/2✓ Branch 0 taken 113 times.
✓ Branch 1 taken 86871 times.
|
86984 | if (alter_info->flags & Alter_info::ENFORCE_CHECK_CONSTRAINT) return true; |
| 20231 | |||
| 20232 |
2/2✓ Branch 0 taken 724 times.
✓ Branch 1 taken 86860 times.
|
87584 | for (auto &cc_spec : alter_info->check_constraint_spec_list) { |
| 20233 |
2/2✓ Branch 0 taken 610 times.
✓ Branch 1 taken 114 times.
|
724 | if (!cc_spec->is_enforced) continue; |
| 20234 | |||
| 20235 | /* | ||
| 20236 | if column is modified then check if type is changed or if default value is | ||
| 20237 | changed. Check constraint re-evaluation is required in this case. | ||
| 20238 | */ | ||
| 20239 |
2/2✓ Branch 0 taken 46 times.
✓ Branch 1 taken 68 times.
|
114 | if (alter_info->flags & Alter_info::ALTER_CHANGE_COLUMN) { |
| 20240 |
5/8✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 46 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 167 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 131 times.
✓ Branch 7 taken 36 times.
|
167 | for (const Create_field &fld : alter_info->create_list) { |
| 20241 | // Get fields used by check constraint. | ||
| 20242 |
1/2✓ Branch 0 taken 131 times.
✗ Branch 1 not taken.
|
131 | mem_root_deque<Item_field *> fields(current_thd->mem_root); |
| 20243 |
1/2✓ Branch 0 taken 131 times.
✗ Branch 1 not taken.
|
131 | cc_spec->check_expr->walk(&Item::collect_item_field_processor, |
| 20244 | enum_walk::POSTFIX, (uchar *)&fields); | ||
| 20245 |
7/12✓ Branch 0 taken 131 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 131 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 254 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 246 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 377 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 254 times.
✓ Branch 11 taken 123 times.
|
377 | for (Item_field *itm_fld : fields) { |
| 20246 |
6/8✓ Branch 0 taken 254 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 252 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 252 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 252 times.
|
254 | if (itm_fld->type() != Item::FIELD_ITEM || itm_fld->field == nullptr) |
| 20247 | 2 | continue; | |
| 20248 | |||
| 20249 | // Check if data type is changed. | ||
| 20250 |
1/2✓ Branch 0 taken 252 times.
✗ Branch 1 not taken.
|
252 | if (!my_strcasecmp(system_charset_info, itm_fld->field_name, |
| 20251 |
4/4✓ Branch 0 taken 82 times.
✓ Branch 1 taken 170 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 244 times.
|
334 | fld.field_name) && |
| 20252 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 74 times.
|
82 | (itm_fld->data_type() != fld.sql_type)) |
| 20253 | 8 | return true; | |
| 20254 | } | ||
| 20255 | |||
| 20256 | /* | ||
| 20257 | If column is modified then default might have changed. Check if | ||
| 20258 | check constraint uses default function. | ||
| 20259 | */ | ||
| 20260 |
4/4✓ Branch 0 taken 38 times.
✓ Branch 1 taken 85 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 121 times.
|
161 | if (fld.change && |
| 20261 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 36 times.
|
38 | cc_spec->check_expr->walk( |
| 20262 | &Item::check_gcol_depend_default_processor, enum_walk::POSTFIX, | ||
| 20263 |
1/2✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
|
38 | reinterpret_cast<uchar *>(const_cast<char *>(fld.change)))) |
| 20264 | 2 | return true; | |
| 20265 |
2/2✓ Branch 0 taken 121 times.
✓ Branch 1 taken 10 times.
|
131 | } |
| 20266 | } | ||
| 20267 | |||
| 20268 | /* | ||
| 20269 | If column is altered to drop or set default then check any check | ||
| 20270 | constraint using the default function. Re-evaluation of check constraint | ||
| 20271 | is required in this case. | ||
| 20272 | */ | ||
| 20273 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 102 times.
|
104 | if (alter_info->flags & Alter_info::ALTER_CHANGE_COLUMN_DEFAULT) { |
| 20274 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
|
3 | for (auto *alter : alter_info->alter_list) { |
| 20275 |
2/6✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
|
2 | if (alter->change_type() == Alter_column::Type::SET_DEFAULT || |
| 20276 | ✗ | alter->change_type() == Alter_column::Type::DROP_DEFAULT) { | |
| 20277 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (cc_spec->check_expr->walk( |
| 20278 | &Item::check_gcol_depend_default_processor, | ||
| 20279 | enum_walk::POSTFIX, | ||
| 20280 | 2 | reinterpret_cast<uchar *>(const_cast<char *>(alter->name)))) | |
| 20281 | 1 | return true; | |
| 20282 | } | ||
| 20283 | } | ||
| 20284 | } | ||
| 20285 | } | ||
| 20286 | |||
| 20287 | 86860 | return false; | |
| 20288 | } | ||
| 20289 | |||
| 20290 | 2193 | bool lock_check_constraint_names_for_rename(THD *thd, const char *db, | |
| 20291 | const char *table_name, | ||
| 20292 | const dd::Table *table_def, | ||
| 20293 | const char *target_db, | ||
| 20294 | const char *target_table_name) { | ||
| 20295 |
1/2✓ Branch 0 taken 2193 times.
✗ Branch 1 not taken.
|
2193 | DBUG_TRACE; |
| 20296 |
1/2✓ Branch 0 taken 2193 times.
✗ Branch 1 not taken.
|
2193 | MDL_request_list mdl_requests; |
| 20297 | 2193 | size_t table_name_len = strlen(table_name); | |
| 20298 | |||
| 20299 | // Push lock requests for the check constraints defined on db.table_name. | ||
| 20300 |
6/10✓ Branch 0 taken 2193 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2193 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2193 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 25 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 25 times.
✓ Branch 9 taken 2193 times.
|
2218 | for (auto &cc : table_def->check_constraints()) { |
| 20301 |
3/6✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 25 times.
|
25 | if (push_check_constraint_mdl_request_to_list(thd, db, cc->name().c_str(), |
| 20302 | mdl_requests)) | ||
| 20303 | ✗ | return true; | |
| 20304 | } | ||
| 20305 | |||
| 20306 | // Push lock request for the check constraints in target table. | ||
| 20307 |
6/10✓ Branch 0 taken 2193 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2193 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2193 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 25 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 25 times.
✓ Branch 9 taken 2193 times.
|
2218 | for (auto &cc : table_def->check_constraints()) { |
| 20308 |
1/2✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
|
25 | const char *cc_name = cc->name().c_str(); |
| 20309 | /* | ||
| 20310 | If check constraint name is a generated name in the source table then | ||
| 20311 | generate name with the target table to create mdl_request with it. | ||
| 20312 | */ | ||
| 20313 |
1/2✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
|
25 | bool is_generated_name = dd::is_generated_check_constraint_name( |
| 20314 |
2/4✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 25 times.
✗ Branch 3 not taken.
|
25 | table_name, table_name_len, cc->name().c_str(), cc->name().length()); |
| 20315 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 7 times.
|
25 | if (is_generated_name) { |
| 20316 | char *end; | ||
| 20317 | uint number = | ||
| 20318 |
1/2✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
|
18 | my_strtoull(cc->name().c_str() + table_name_len + |
| 20319 | 18 | sizeof(dd::CHECK_CONSTRAINT_NAME_SUBSTR) - 1, | |
| 20320 | 18 | &end, 10); | |
| 20321 | LEX_STRING name; | ||
| 20322 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
|
18 | if (generate_check_constraint_name(thd, target_table_name, number, name, |
| 20323 | true)) | ||
| 20324 | ✗ | return true; | |
| 20325 | 18 | cc_name = name.str; | |
| 20326 | } | ||
| 20327 | |||
| 20328 | /* | ||
| 20329 | If check constraint name is generated or table moved different database | ||
| 20330 | then create mdl_request with target_db.cc_name. | ||
| 20331 | */ | ||
| 20332 | 32 | if ((is_generated_name || | |
| 20333 |
6/8✓ Branch 0 taken 7 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 6 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 25 times.
|
44 | my_strcasecmp(table_alias_charset, db, target_db)) && |
| 20334 |
2/4✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 19 times.
|
19 | push_check_constraint_mdl_request_to_list(thd, target_db, cc_name, |
| 20335 | mdl_requests)) | ||
| 20336 | ✗ | return true; | |
| 20337 | } | ||
| 20338 | |||
| 20339 | // Acquire locks on all the collected check constraint names. | ||
| 20340 |
3/4✓ Branch 0 taken 14 times.
✓ Branch 1 taken 2179 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2193 times.
|
2207 | if (!mdl_requests.is_empty() && |
| 20341 |
2/4✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 14 times.
|
14 | thd->mdl_context.acquire_locks(&mdl_requests, |
| 20342 | thd->variables.lock_wait_timeout)) | ||
| 20343 | ✗ | return true; | |
| 20344 | |||
| 20345 |
2/4✓ Branch 0 taken 2193 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2193 times.
✗ Branch 3 not taken.
|
2193 | DEBUG_SYNC(thd, "after_acquiring_lock_on_check_constraints_for_rename"); |
| 20346 | |||
| 20347 | 2193 | return false; | |
| 20348 | 2193 | } | |
| 20349 | |||
| 20350 | 151509 | bool lock_check_constraint_names(THD *thd, TABLE_LIST *tables) { | |
| 20351 |
1/2✓ Branch 0 taken 151509 times.
✗ Branch 1 not taken.
|
151509 | DBUG_TRACE; |
| 20352 | 151509 | MEM_ROOT mdl_reqs_root(key_memory_rm_db_mdl_reqs_root, MEM_ROOT_BLOCK_SIZE); | |
| 20353 |
1/2✓ Branch 0 taken 151509 times.
✗ Branch 1 not taken.
|
151509 | MDL_request_list mdl_requests; |
| 20354 | |||
| 20355 |
2/2✓ Branch 0 taken 188936 times.
✓ Branch 1 taken 151509 times.
|
340445 | for (TABLE_LIST *table = tables; table != nullptr; |
| 20356 | 188936 | table = table->next_local) { | |
| 20357 |
6/6✓ Branch 0 taken 177834 times.
✓ Branch 1 taken 11102 times.
✓ Branch 2 taken 43041 times.
✓ Branch 3 taken 134793 times.
✓ Branch 4 taken 43041 times.
✓ Branch 5 taken 145895 times.
|
201062 | if (table->open_type != OT_BASE_ONLY && is_temporary_table(table)) continue; |
| 20358 | |||
| 20359 |
1/2✓ Branch 0 taken 145895 times.
✗ Branch 1 not taken.
|
145895 | dd::cache::Dictionary_client::Auto_releaser releaser(thd->dd_client()); |
| 20360 | |||
| 20361 | 145895 | const dd::Abstract_table *abstract_table_def = nullptr; | |
| 20362 |
4/8✓ Branch 0 taken 145895 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 145895 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 145895 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 145895 times.
|
145895 | if (thd->dd_client()->acquire(table->db, table->table_name, |
| 20363 | &abstract_table_def)) | ||
| 20364 | ✗ | return true; | |
| 20365 | |||
| 20366 |
4/4✓ Branch 0 taken 134636 times.
✓ Branch 1 taken 11259 times.
✓ Branch 2 taken 12126 times.
✓ Branch 3 taken 133769 times.
|
280531 | if (abstract_table_def == nullptr || |
| 20367 |
3/4✓ Branch 0 taken 134636 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 867 times.
✓ Branch 3 taken 133769 times.
|
134636 | abstract_table_def->type() != dd::enum_table_type::BASE_TABLE) |
| 20368 | 12126 | continue; | |
| 20369 | |||
| 20370 | const dd::Table *table_def = | ||
| 20371 |
1/2✓ Branch 0 taken 133769 times.
✗ Branch 1 not taken.
|
133769 | dynamic_cast<const dd::Table *>(abstract_table_def); |
| 20372 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 133769 times.
|
133769 | assert(table_def != nullptr); |
| 20373 | |||
| 20374 | /* | ||
| 20375 | Ensure that we don't hold memory used by MDL_requests after locks | ||
| 20376 | have been acquired. This reduces memory usage in cases when we have | ||
| 20377 | DROP DATABASE that needs to drop lots of different objects. | ||
| 20378 | */ | ||
| 20379 | 133769 | MEM_ROOT *save_thd_mem_root = thd->mem_root; | |
| 20380 | auto restore_thd_mem_root = | ||
| 20381 |
1/2✓ Branch 0 taken 133769 times.
✗ Branch 1 not taken.
|
133769 | create_scope_guard([&]() { thd->mem_root = save_thd_mem_root; }); |
| 20382 | 133769 | thd->mem_root = &mdl_reqs_root; | |
| 20383 | |||
| 20384 |
6/10✓ Branch 0 taken 133769 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 133769 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 133769 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 646 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 646 times.
✓ Branch 9 taken 133769 times.
|
134415 | for (auto &cc : table_def->check_constraints()) { |
| 20385 |
2/4✓ Branch 0 taken 646 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 646 times.
|
646 | if (push_check_constraint_mdl_request_to_list( |
| 20386 |
1/2✓ Branch 0 taken 646 times.
✗ Branch 1 not taken.
|
646 | thd, table->db, cc->name().c_str(), mdl_requests)) |
| 20387 | ✗ | return false; | |
| 20388 | } | ||
| 20389 |
3/5✓ Branch 0 taken 133769 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 133769 times.
✓ Branch 3 taken 12126 times.
✗ Branch 4 not taken.
|
145895 | } |
| 20390 | |||
| 20391 | // Acquire MDL lock on all the check constraint names. | ||
| 20392 |
3/4✓ Branch 0 taken 371 times.
✓ Branch 1 taken 151138 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 151509 times.
|
151880 | if (!mdl_requests.is_empty() && |
| 20393 |
2/4✓ Branch 0 taken 371 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 371 times.
|
371 | thd->mdl_context.acquire_locks(&mdl_requests, |
| 20394 | thd->variables.lock_wait_timeout)) | ||
| 20395 | ✗ | return true; | |
| 20396 | |||
| 20397 | 151509 | return false; | |
| 20398 | 151509 | } | |
| 20399 |